原题地址
【题目大意】
不想打了。
【题目分析】
每一位不会互相影响,可以把每一位分开考虑。
还要用unsigned long long。
【解题思路】
将每一位分开以后修改好啊,直接改就好了。
询问的时候算出来每一位填0,1经过这条链的变换之后得到的值。
我们发现从高位往低位走的时候,如果这一位填0可以得到1,那么填0一定是最优的。
否则如果可以填1,就把这一位填为1。
复杂度是 nklog2n (树剖)或者 nklogn (LCT),只能通过50%的数据
然后我们决定把这个k搞掉。
只要把k位一起算就可以了,多维护几个值就好。
复杂度是 O(nklog2n) (树剖)或者 O(nklogn) (LCT)
【代码】
#include
#include
#include
#include
using namespace std;
typedef unsigned long long ULL;
const ULL mx=0-1;
const int MAXN=2e5+10;
int n,m,k,tot,sz;
int opt[MAXN],siz[MAXN],dep[MAXN],q[MAXN],pos[MAXN];
int head[MAXN],top[MAXN],son[MAXN],fa[MAXN];
ULL val[MAXN],cf[MAXN];
struct Tway
{
int v,nex;
};
Tway e[MAXN<<1];
struct Tree
{
ULL v0,v1,w0,w1;
};
Tree tree[MAXN<<2],ans0[MAXN],ans1[MAXN];
inline void add(int u,int v)
{
++tot;
e[tot].v=v;e[tot].nex=head[u];head[u]=tot;
}
inline void dfs0(int u,int f)
{
siz[u]=1;dep[u]=dep[f]+1;
for(int i=head[u];i;i=e[i].nex)
{
int v=e[i].v;
if(v==f)
continue;
fa[v]=u;
dfs0(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])
son[u]=v;
}
}
inline void dfs1(int u,int tp)
{
// printf("%d\n",u);
top[u]=tp;pos[u]=++sz;q[sz]=u;
if(!son[u])
return;
dfs1(son[u],tp);
for(int i=head[u];i;i=e[i].nex)
{
int v=e[i].v;
if(v!=fa[u] && v!=son[u])
dfs1(v,v);
}
}
inline ULL calc(ULL num,int u)
{
if(opt[u]==1) return num&val[u];
if(opt[u]==2) return num|val[u];
if(opt[u]==3) return num^val[u];
}
inline Tree update(Tree l,Tree r)
{
Tree tmp;
tmp.v0=tmp.v1=tmp.w0=tmp.w1=0;
tmp.v0=(l.v0 & r.v1) | ((~l.v0)&r.v0);
tmp.v1=(l.v1 & r.v1) | ((~l.v1)&r.v0);
tmp.w0=(r.w0 & l.w1) | ((~r.w0)&l.w0);
tmp.w1=(r.w1 & l.w1) | ((~r.w1)&l.w0);//typed wrong
return tmp;
}
inline void pushup(int rt)
{
tree[rt]=update(tree[rt<<1],tree[rt<<1|1]);
}
inline void build(int rt,int l,int r)
{
if(l==r)
{
int tmp=q[l];
tree[rt].v0=tree[rt].w0=calc(0,tmp);
tree[rt].v1=tree[rt].w1=calc(mx,tmp);
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
inline void changep(int rt,int l,int r,int p)
{
if(l==r && l==p)
{
int tmp=q[l];
tree[rt].v0=tree[rt].w0=calc(0,tmp);
tree[rt].v1=tree[rt].w1=calc(mx,tmp);
return;
}
int mid=(l+r)>>1;
if(p<=mid)
changep(rt<<1,l,mid,p);
else
changep(rt<<1|1,mid+1,r,p);
pushup(rt);
}
inline Tree query(int rt,int l,int r,int L,int R)
{
if(L<=l && r<=R)
return tree[rt];
int mid=(l+r)>>1;
Tree ret;bool flag=false;
if(L<=mid)
ret=query(rt<<1,l,mid,L,R),flag=true;
if(R>mid)
if(flag)
ret=update(ret,query(rt<<1|1,mid+1,r,L,R));
else
ret=query(rt<<1|1,mid+1,r,L,R);
return ret;
}
inline Tree solve(int x,int y)
{
int cnt0=0,cnt1=0;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
{
ans0[++cnt0]=query(1,1,n,pos[top[x]],pos[x]);
x=fa[top[x]];
}
else
{
ans1[++cnt1]=query(1,1,n,pos[top[y]],top[y]);
y=fa[top[y]];
}
}
if(dep[x]>=dep[y])
ans0[++cnt0]=query(1,1,n,pos[y],pos[x]);
else
ans1[++cnt1]=query(1,1,n,pos[x],pos[y]);
for(int i=1;i<=cnt0;++i)
swap(ans0[i].v0,ans0[i].w0),swap(ans0[i].v1,ans0[i].w1);//swap false first
Tree sum;
if(cnt0)
{
sum=ans0[1];
for(int i=2;i<=cnt0;++i)
sum=update(sum,ans0[i]);
if(cnt1)
sum=update(sum,ans1[cnt1]);
}
else
sum=ans1[cnt1];
for(int i=cnt1-1;i>=1;--i)
sum=update(sum,ans1[i]);
printf("%d %d %d %d\n",sum.v0,sum.v1,sum.w0,sum.w1);
return sum;
}
int main()
{
freopen("LGP3613.in","r",stdin);
freopen("LGP3613.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
cf[0]=1;
for(int i=1;i<=k-1;++i)
cf[i]=(cf[i-1]<<1);
for(int i=1;i<=n;++i)
scanf("%d%llu",&opt[i],&val[i]);
for(int i=1;iint u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
dfs0(1,0);dfs1(1,1);
build(1,1,n);
for(int i=1;i<=m;++i)
{
int op,u,v;ULL t;
scanf("%d%d%d%llu",&op,&u,&v,&t);
if(op&1)
{
Tree tmp=solve(u,v);ULL ret=0;
for(int i=63;i>=0;--i)
{
ULL t0=(tmp.v0>>i)&1;
ULL t1=(tmp.v1>>i)&1;
if(t0>=t1 || cf[i]>t)
ret|=(t0 ? cf[i] : 0);
else
{
ret|=(t1 ? cf[i] : 0);
t-=cf[i];
}
}
printf("%llu\n",ret);
}
else
{
opt[u]=v;val[u]=t;
changep(1,1,n,pos[u]);
}
}
return 0;
}