洛谷P3613 睡觉困难综合征
2018-08-06 16:27
204 查看
传送门
[b]题解[/b]
人生第一道由乃……
做这题之前应该先去把这一题给切掉->这里
我的题解->这里
然后先膜一波zsy大佬和flashhu大佬
大体思路就是先吧全0和全1的都跑答案,然后按位贪心
我一开始想到的是每一次split,然后直接一个一个跑
后来发现时间复杂度肯定爆炸……
看了看网上其他的,发现说的都不怎么清楚……结果硬是理解了好久才明白……
先考虑一下LCT维护什么
定义$f0$为全0走过一条路径之后的答案,$f1$表示全1走过一条路径之后的答案
LCT需要维护的是splay中以x为根的子树里,从前往后遍历(即中序遍历)的$f0$和$f1$以及从后往前(即与前面完全相反的顺序)的$f0$和$f1$
比如有一棵splay,x是其中一个点,它在splay中有两个儿子,左儿子y和右儿子z,那么从前往后遍历就是路径y->x->z,从后往前就是路径z->x->y
然后思考,如果已经有了两个区间,该如何合并他们
假如说我们有两段计算出答案的区间,分别对应f0,f1和g0,g1。我们设合并后的答案是h0,h1,那么有如下式子:
$h0=(~f0&g0)+(f0&g1)$
$h1=(~f1&g0)+(f1&g1)$
为啥?
全0走到最后的话,先考虑两种情况
全0走到中间等于1的那几位,走后一半的答案等同于全1走后一半的这几位的答案
全0走到中间等于0的那几位,走后一半的答案等同于全0走后一半的这几位的答案
只需要把这两个答案加起来即可
(ps:这里默认f为前一半的答案,g为后一半的答案)
全1走到最后同理
然后就是几个细节
1.pushdown的时候因为有翻转标记,从前往后走和从后往前走的答案也要交换
2.按位贪心用1做位运算的时候,记得把1设成unsigned long long(简单来说就是设一个ull变量让它等于1)(我就是因为一开始直接用1做位运算结果死都调不出来……)
[b]题解[/b]
人生第一道由乃……
做这题之前应该先去把这一题给切掉->这里
我的题解->这里
然后先膜一波zsy大佬和flashhu大佬
大体思路就是先吧全0和全1的都跑答案,然后按位贪心
我一开始想到的是每一次split,然后直接一个一个跑
后来发现时间复杂度肯定爆炸……
看了看网上其他的,发现说的都不怎么清楚……结果硬是理解了好久才明白……
先考虑一下LCT维护什么
定义$f0$为全0走过一条路径之后的答案,$f1$表示全1走过一条路径之后的答案
LCT需要维护的是splay中以x为根的子树里,从前往后遍历(即中序遍历)的$f0$和$f1$以及从后往前(即与前面完全相反的顺序)的$f0$和$f1$
比如有一棵splay,x是其中一个点,它在splay中有两个儿子,左儿子y和右儿子z,那么从前往后遍历就是路径y->x->z,从后往前就是路径z->x->y
然后思考,如果已经有了两个区间,该如何合并他们
假如说我们有两段计算出答案的区间,分别对应f0,f1和g0,g1。我们设合并后的答案是h0,h1,那么有如下式子:
$h0=(~f0&g0)+(f0&g1)$
$h1=(~f1&g0)+(f1&g1)$
为啥?
全0走到最后的话,先考虑两种情况
全0走到中间等于1的那几位,走后一半的答案等同于全1走后一半的这几位的答案
全0走到中间等于0的那几位,走后一半的答案等同于全0走后一半的这几位的答案
只需要把这两个答案加起来即可
(ps:这里默认f为前一半的答案,g为后一半的答案)
全1走到最后同理
然后就是几个细节
1.pushdown的时候因为有翻转标记,从前往后走和从后往前走的答案也要交换
2.按位贪心用1做位运算的时候,记得把1设成unsigned long long(简单来说就是设一个ull变量让它等于1)(我就是因为一开始直接用1做位运算结果死都调不出来……)
// luogu-judger-enable-o2 //minamoto #include<iostream> #include<cstdio> #define ll unsigned long long using std::swap; using std::cout; using std::endl; #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) char buf[1<<21],*p1=buf,*p2=buf; inline ll read(){ #define num ch-'0' char ch;bool flag=0;ll res; while(!isdigit(ch=getc())) (ch=='-')&&(flag=true); for(res=num;isdigit(ch=getc());res=res*10+num); (flag)&&(res=-res); #undef num return res; } char obuf[1<<24],*o=obuf; void print(ll x){ if(x>9) print(x/10); *o++=x%10+48; } const int N=100005; struct node{ ll f0,f1; inline node operator +(const node &b)const { node a; a.f0=(~f0&b.f0)|(f0&b.f1); a.f1=(~f1&b.f0)|(f1&b.f1); return a; } }f ,l ,r ; int fa ,ch [2],s ,rev ,top,tot; int ver[N<<1],head ,Next[N<<1]; inline void add(int u,int v){ ver[++tot]=v,Next[tot]=head[u],head[u]=tot; ver[++tot]=u,Next[tot]=head[v],head[v]=tot; } inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} #define ls ch[x][0] #define rs ch[x][1] inline void pushup(int x){ l[x]=r[x]=f[x]; if(ls) l[x]=l[ls]+l[x],r[x]=r[x]+r[ls]; if(rs) l[x]=l[x]+l[rs],r[x]=r[rs]+r[x]; } inline void pushr(int x){ swap(ls,rs),swap(l[x],r[x]),rev[x]^=1; } inline void pushdown(int x){ if(rev[x]&&x){ pushr(ls),pushr(rs),rev[x]=0; } } void rotate(int x){ int y=fa[x],z=fa[y],d=ch[y][1]==x; if(!isroot(y)) ch[z][ch[z][1]==y]=x; fa[x]=z,fa[y]=x,fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y,pushup(y); } void splay(int x){ s[top=1]=x;for(int i=x;!isroot(i);i=fa[i]) s[++top]=fa[i]; while(top) pushdown(s[top--]); for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){ if(!isroot(y)) ((ch[y][1]==x)^(ch[z][1]==y))?rotate(x):rotate(y); rotate(x); } pushup(x); } void access(int x){ for(int y=0;x;x=fa[y=x]){ splay(x),rs=y,pushup(x); } } void makeroot(int x){ access(x),splay(x),pushr(x); } void split(int x,int y){ makeroot(x),access(y),splay(y); } void dfs(int u){ for(int i=head[u];i;i=Next[i]){ int v=ver[i]; if(v==fa[u]) continue; fa[v]=u,dfs(v); } pushup(u); } int main(){ //freopen("testdata.in","r",stdin); int n=read(),m=read(),k=read(); for(int i=1;i<=n;++i){ int x=read();ll y=read(); switch(x){ case 1:f[i]=(node){0,y};break; case 2:f[i]=(node){y,~0};break; case 3:f[i]=(node){y,~y};break; } } for(int i=1;i<n;++i){ int u=read(),v=read();add(u,v); } dfs(1); while(m--){ int opt=read(),x=read(),y=read();ll z=read(); if(opt&1){ split(x,y);ll ans=0,e=1; for(int i=k-1;i>=0;--i){ if(l[y].f0&(e<<i)) ans|=e<<i; else if((l[y].f1&(e<<i))&&z>=(e<<i)) ans|=e<<i,z^=e<<i; } print(ans),*o++='\n'; } else{ switch(y){ case 1:f[x]=(node){0,z};break; case 2:f[x]=(node){z,~0};break; case 3:f[x]=(node){z,~z};break; } splay(x); } } fwrite(obuf,o-obuf,1,stdout); return 0; }
相关文章推荐
- 洛谷P3613 睡觉困难综合征
- 【树链剖分】LGP3613 睡觉困难综合征
- Luogu3613 睡觉困难综合征
- Luogu3613 睡觉困难综合征
- luogu3613 睡觉困难综合征(lct+贪心)
- [洛谷]P3613 睡觉困难综合征
- luogu3613 睡觉困难综合征
- Luogu 睡觉困难综合征 ([NOI2014]起床困难综合症)
- 省队集训Day1 睡觉困难综合征
- 洛谷P3613:睡觉困难综合征 (LCT+二进制压位)
- luogu P3613 睡觉困难综合征
- [bzoj3668][Noi2014]起床困难综合症/[洛谷3613]睡觉困难综合症
- [YNOI2017][bzoj4811][luogu3613] 由乃的OJ/睡觉困难综合症 [压位+树链剖分+线段树]
- 【NOI 2014】起床困难综合征 拆位+贪心
- 2017.10.19 起床困难综合征 思考记录
- 洛谷3613:睡觉困难综合症(LCT+机巧的位运算)
- [BZOJ3668]NOI2014起床困难综合征|贪心
- [UOJ#2] [NOI2014] 起床困难综合征
- 双休日,只有发呆睡觉!
- 睡觉时间越来越晚了