题解: 上一题的系列套路题 但是上一题 我们用n*log^3(n)水过了 这题6s明显是不可行的 需要优化一下复杂度 我们考虑线段树合并 维护每一位输入为0/1的时候输出 然后做区间合并 这样子平方转移依然是3个log的 我们想想二进制优化 让每一位对应unsigned long long每一二进制位然后把每次合并后的结果都用一个64位无符号整数存下来 这样就成2个log了 具体怎么合并 可以手推下
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=1e5+10; const double eps=1e-8; #define ll unsigned long long #define pii pair<ll,ll> using namespace std; struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e; void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;} inline ll read() { ll ret=0; char gc=getchar(); while(gc<'0'||gc>'9') gc=getchar(); while(gc>='0'&&gc<='9') ret=ret*10+(gc-'0'),gc=getchar(); return ret; } ll l0[MAXN<<2],l1[MAXN<<2],r0[MAXN<<2],r1[MAXN<<2]; int opt[MAXN],n,m,k; ll a[MAXN],base; void up(int x){ l0[x]=(l1[x<<1|1]&l0[x<<1])|((~l0[x<<1])&l0[x<<1|1]); l1[x]=(l1[x<<1]&l1[x<<1|1])|((~l1[x<<1])&l0[x<<1|1]); r0[x]=(r0[x<<1|1]&r1[x<<1])|((~r0[x<<1|1])&r0[x<<1]); r1[x]=(r1[x<<1|1]&r1[x<<1])|((~r1[x<<1|1])&r0[x<<1]); } void Opt1(int x,ll y){ l0[x]=r0[x]=0; l1[x]=r1[x]=y; } void Opt2(int x,ll y){ l0[x]=r0[x]=y; l1[x]=r1[x]=base; } void Opt3(int x,ll y){ l0[x]=r0[x]=y; l1[x]=r1[x]=(base^y); } int tp[MAXN],p[MAXN],fp[MAXN],cnt; void built(int x,int l,int r){ if(l==r){ if(opt[fp[l]]==1)Opt1(x,a[fp[l]]); else if(opt[fp[l]]==2)Opt2(x,a[fp[l]]); else Opt3(x,a[fp[l]]); return ; } int mid=(l+r)>>1; built(x<<1,l,mid); built(x<<1|1,mid+1,r); up(x); } void update(int x,int l,int r,int t){ if(l==r){ if(opt[fp[l]]==1)Opt1(x,a[fp[l]]); else if(opt[fp[l]]==2)Opt2(x,a[fp[l]]); else Opt3(x,a[fp[l]]); return ; } int mid=(l+r)>>1; if(t<=mid)update(x<<1,l,mid,t); else update(x<<1|1,mid+1,r,t); up(x); } pii ans; void query1(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ ans.first=(ans.first&l1[x])|(~ans.first&l0[x]); ans.second=(ans.second&l1[x])|(~ans.second&l0[x]); return ; } int mid=(l+r)>>1; if(ql<=mid)query1(x<<1,l,mid,ql,qr); if(qr>mid)query1(x<<1|1,mid+1,r,ql,qr); } void query2(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ ans.first=(ans.first&r1[x])|(~ans.first&r0[x]); ans.second=(ans.second&r1[x])|(~ans.second&r0[x]); return ; } int mid=(l+r)>>1; if(qr>mid)query2(x<<1|1,mid+1,r,ql,qr); if(ql<=mid)query2(x<<1,l,mid,ql,qr); } int son[MAXN],num[MAXN],dep[MAXN],fa[MAXN]; void dfs1(int x,int pre,int deep){ fa[x]=pre;num[x]=1;dep[x]=deep+1; link(x)if(j->t!=pre){ dfs1(j->t,x,deep+1); num[x]+=num[j->t]; if(son[x]==-1||num[son[x]]<num[j->t])son[x]=j->t; } } void dfs2(int x,int td){ tp[x]=td;p[x]=++cnt;fp[p[x]]=x; if(son[x]!=-1)dfs2(son[x],td); link(x)if(j->t!=son[x]&&j->t!=fa[x])dfs2(j->t,j->t); } pii st[MAXN];int tot; void solve(int u,int v,ll z){ int uu=tp[u];int vv=tp[v]; ans.first=0;ans.second=base; tot=0; while(uu!=vv){ if(dep[uu]>dep[vv])query2(1,1,n,p[uu],p[u]),u=fa[uu],uu=tp[u]; else st[++tot]=mp(p[vv],p[v]),v=fa[vv],vv=tp[v]; } if(dep[u]>dep[v])query2(1,1,n,p[v],p[u]); else query1(1,1,n,p[u],p[v]); dec(i,tot,1)query1(1,1,n,st[i].first,st[i].second); ll ans1=0;ll maxx=0; for(int i=k-1;i>=0;i--){ int t1=((ans.first>>i)&1); int t2=((ans.second>>i)&1); if(t1&&t2)maxx+=(1ll<<i); else if(t1&&!t2)maxx+=(1ll<<i); else if(!t1&&t2){ if(ans1+(1ll<<i)<=z)ans1+=(1ll<<i),maxx+=(1ll<<i); } } printf("%llu ",maxx); } int main(){ n=read();m=read();k=read(); for(int i=0;i<k;i++)base|=(1ULL<<i); inc(i,1,n)son[i]=-1; inc(i,1,n)opt[i]=read(),a[i]=read(); int u,v; inc(i,2,n)u=read(),v=read(),add(u,v),add(v,u); dfs1(1,0,0);dfs2(1,1);built(1,1,n); int x,y,op;ll z; while(m--){ op=read();x=read();y=read();z=read(); if(op==1)solve(x,y,z); else opt[x]=y,a[x]=z,update(1,1,n,p[x]); } return 0; }
4811: [Ynoi2017]由乃的OJ
Time Limit: 6 Sec Memory Limit: 256 MBSubmit: 740 Solved: 271
[Submit][Status][Discuss]
Description
由乃正在做她的OJ。现在她在处理OJ上的用户排名问题。OJ上注册了n个用户,编号为1~",一开始他们按照编号
排名。由乃会按照心情对这些用户做以下四种操作,修改用户的排名和编号:然而由乃心情非常不好,因为Deus天
天问她题。。。因为Deus天天问由乃OI题,所以由乃去学习了一下OI,由于由乃智商挺高,所以OI学的特别熟练她
在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送
Deus:这个题怎么做呀?
yuno:这个不是NOI2014的水题吗。。。
Deus:那如果出到树上,多组链询问,带修改呢?
yuno:诶。。。???
Deus:这题叫做睡觉困难综合征哟~
虽然由乃OI很好,但是她基本上不会DS,线段树都只会口胡,比如她NOI2016的分数就是100+100+100+0+100+100。
。。NOIP2017的分数是100+0+100+100+0+100所以她还是只能找你帮她做了。。。
给你一个有n个点的树,每个点的包括一个位运算opt和一个权值x,位运算有&,l,^三种,分别用1,2,3表示。
每次询问包含三个数x,y,z,初始选定一个数v。然后v依次经过从x到y的所有节点,每经过一个点i,v就变成v opti
xi,所以他想问你,最后到y时,希望得到的值尽可能大,求最大值?给定的初始值v必须是在[0,z]之间。每次修
改包含三个数x,y,z,意思是把x点的操作修改为y,数值改为z
Input
第一行三个数n,m,k。k的意义是每个点上的数,以及询问中的数值z都 <2^k。之后n行
每行两个数x,y表示该点的位运算编号以及数值
之后n - 1行,每行两个数x,y表示x和y之间有边相连
之后m行,每行四个数,Q,x,y,z表示这次操作为Q(1位询问,2为修改),x,y,z意义如题所述
0 <= n , m <= 100000 , k <= 64
Output
对于每个操作1,输出到最后可以造成的最大刺激度v
Sample Input
5 5 3
1 7
2 6
3 7
3 6
3 1
1 2
2 3
3 4
1 5
1 1 4 7
1 1 3 5
2 1 1 3
2 3 3 3
1 1 3 2
1 7
2 6
3 7
3 6
3 1
1 2
2 3
3 4
1 5
1 1 4 7
1 1 3 5
2 1 1 3
2 3 3 3
1 1 3 2
Sample Output
7
1
5
1
5