思路:
感覺這題也可神了..
(還是我太弱)
首先發現每一位不會互相影響,可以把每一位分開考慮,然后用樹鏈剖分或者LCT維護這個樹
修改直接修改,詢問的時候算出來每一位填0,1經過這條鏈的變換之后得到的值
考慮貪心,從高往低,如果這一位填0可以得到1,那么填0一定是最優的
否則如果可以填1,就把這一位填為1
復雜度是nklog^2n或者nklogn,只能通過50%的數據
發現可以并行計算這k位,復雜度降為nlog^2n的樹鏈剖分或者nlogn的LCT,可以通過100%的數據
這個題沒有卡常,合并信息不是O( 1 )的算法沒有通過是很正常的吧。。。
還有樹鏈剖分沒法做到logn,每條鏈建線段樹也是log^2n的,還不能搞子樹,似乎常數也一般。。。
最優復雜度是log^2n,不過期望下大概是lognloglogn的感覺
這個題的最優復雜度為O( n + q( logn + k ) ),至少目前來說是這樣的
from 洛谷的題解.
unsigned long long +各種位運算
線段樹要分別維護向上的和向下的
?
//By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=100005; typedef unsigned long long ull; ull a[N],zz,now,ans; int n,m,k,op,xx,yy,Op[N],first[N],next[N*2],v[N*2],tot; int size[N],fa[N],son[N],deep[N],rev[N],dfn[N],cnt,top[N]; struct Tree{ull v0,v1;Tree(){}Tree(int op,ull x){if(op==1)v0=0,v1=x;else if(op==2)v0=x,v1=~0;else v0=x,v1=(~0)^x;}Tree(ull x,ull y){v0=x,v1=y;} }trl[N*8],trr[N*8]; Tree operator+(Tree x,Tree y){return Tree((x.v0&y.v1)|((~x.v0)&y.v0),(x.v1&y.v1)|((~x.v1)&y.v0));} void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;} void dfs(int x){size[x]=1;for(int i=first[x];~i;i=next[i])if(v[i]!=fa[x]){fa[v[i]]=x,deep[v[i]]=deep[x]+1,dfs(v[i]),size[x]+=size[v[i]];if(size[v[i]]>size[son[x]])son[x]=v[i];} } void dfs2(int x,int tp){rev[dfn[x]=++cnt]=x;top[x]=tp;if(son[x])dfs2(son[x],tp);for(int i=first[x];~i;i=next[i])if(v[i]!=fa[x]&&v[i]!=son[x])dfs2(v[i],v[i]); } void build(int l,int r,int pos){if(l==r){trl[pos]=trr[pos]=Tree(Op[rev[l]],a[rev[l]]);return;}int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;build(l,mid,lson),build(mid+1,r,rson);trl[pos]=trl[lson]+trl[rson],trr[pos]=trr[rson]+trr[lson]; } void insert(int l,int r,int pos,int num){if(l==r){trl[pos]=trr[pos]=Tree(Op[rev[l]],a[rev[l]]);return;}int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;if(mid<num)insert(mid+1,r,rson,num);else insert(l,mid,lson,num);trl[pos]=trl[lson]+trl[rson],trr[pos]=trr[rson]+trr[lson]; } Tree query(int l,int r,int pos,int L,int R,int f){if(l>=L&&r<=R)return f?trr[pos]:trl[pos];int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;if(mid<L)return query(mid+1,r,rson,L,R,f);else if(mid>=R)return query(l,mid,lson,L,R,f);else{if(!f)return query(l,mid,lson,L,R,f)+query(mid+1,r,rson,L,R,f);else return query(mid+1,r,rson,L,R,f)+query(l,mid,lson,L,R,f);} } Tree solve(int x,int y){Tree vx=Tree((int)3,0ull),vy=Tree((int)3,0ull);int fx=top[x],fy=top[y];while(fx!=fy)if(deep[fx]>deep[fy])vx=vx+query(1,n,1,dfn[fx],dfn[x],1),x=fa[fx],fx=top[x];else vy=query(1,n,1,dfn[fy],dfn[y],0)+vy,y=fa[fy],fy=top[y];if(deep[x]>deep[y])return vx+query(1,n,1,dfn[y],dfn[x],1)+vy;return vx+query(1,n,1,dfn[x],dfn[y],0)+vy; } int main(){memset(first,-1,sizeof(first)),deep[1]=1;scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=n;i++)scanf("%d%llu",&Op[i],&a[i]);for(int i=1;i<n;i++)scanf("%d%d",&xx,&yy),add(xx,yy),add(yy,xx);dfs(1),dfs2(1,1),build(1,n,1);while(m--){scanf("%d%d%d%llu",&op,&xx,&yy,&zz);if(op==2)Op[xx]=yy,a[xx]=zz,insert(1,n,1,dfn[xx]);else{Tree t=solve(xx,yy);now=ans=0;for(int i=k-1;~i;i--)if(t.v0&(1ull<<i))ans+=1ull<<i;else if(t.v1&(1ull<<i)&&now+(1ull<<i)<=zz)now+=1ull<<i,ans+=1ull<<i;printf("%llu\n",ans);}} }
?