T1 bzoj 4730 Alice和Bob又在玩游戏
题目大意:
Alice和Bob在玩游戏 n个节点,m条边(0<=m<=n-1),构成若干棵有根树,每棵树的根节点是该连通块内编号最小的点
Alice和Bob轮流操作,每回合选择一个没有被删除的节点x,将x及其所有祖先全部删除,不能操作的人输
思路:
根据博弈论的一些定理可以得到一个优秀的$n^2$做法
由$SG$定理得 每个点的$SG$函数值为$mex${子树内一个点的SG xor 该根节点其余儿子的SG}
因此对于每个点我们可以开一个trie树表示这个点的SG集合
合并的时候每个子树的$trie$树$xor$其余子树的$xor$和 然后像线段树合并一样合并$trie$树即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #define rep(i,s,t) for(register int i=(s);i<=(t);++i) 11 #define dwn(i,s,t) for(register int i=(s);i>=(t);--i) 12 #define ren for(register int i=fst[x];i;i=nxt[i]) 13 #define Fill(x,t) memset(x,t,sizeof(x)) 14 #define ll long long 15 #define inf 2139062143 16 #define MAXN 200100 17 using namespace std; 18 inline int read() 19 { 20 int x=0,f=1;char ch=getchar(); 21 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 22 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 23 return x*f; 24 } 25 int n,m,fst[MAXN],to[MAXN<<1],nxt[MAXN<<1],cnt,vis[MAXN],sg[MAXN]; 26 int ls[MAXN*20],rs[MAXN*20],tag[MAXN*20],tot,ans,sz[MAXN*20],rt[MAXN*20]; 27 const int maxDep=16; 28 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 29 void pshd(int k,int Dep) 30 { 31 if((tag[k]>>Dep)&1) swap(ls[k],rs[k]); 32 tag[k]&=((1<<Dep)-1); 33 tag[ls[k]]^=tag[k],tag[rs[k]]^=tag[k],tag[k]=0; 34 } 35 int merge(int x,int y,int Dep) 36 { 37 if(!(x*y)) return x|y; 38 pshd(x,Dep);pshd(y,Dep); 39 ls[x]=merge(ls[x],ls[y],Dep-1),rs[x]=merge(rs[x],rs[y],Dep-1); 40 return x; 41 } 42 void ins(int &x,int val,int Dep) 43 { 44 if(!x) x=++tot,sz[x]=1,ls[x]=rs[x]=tag[x]=0;if(!(~Dep)) return ; 45 pshd(x,Dep);ins((val&(1<<Dep))?rs[x]:ls[x],val,Dep-1); 46 sz[x]=sz[ls[x]]+sz[rs[x]]; 47 } 48 int mex(int x,int res=0) 49 { 50 dwn(i,maxDep,0) 51 { 52 if(sz[ls[x]]<(1<<i)) x=ls[x]; 53 else res|=(1<<i),x=rs[x]; 54 } 55 return res; 56 } 57 void dfs(int x,int fa) 58 { 59 int sum=0;vis[x]=1; 60 ren if(to[i]!=fa) {dfs(to[i],x);sum^=sg[to[i]];} 61 ren if(to[i]!=fa) {tag[rt[to[i]]]^=(sum^sg[to[i]]);rt[x]=merge(rt[x],rt[to[i]],maxDep);} 62 ins(rt[x],sum,maxDep);sg[x]=mex(rt[x]); 63 } 64 int main() 65 { 66 int T=read(); 67 while(T--) 68 { 69 n=read(),m=read(),tot=cnt=ans=0;int a,b; 70 while(m--) {a=read(),b=read();add(a,b);add(b,a);} 71 rep(i,1,n) if(!vis[i]) {dfs(i,0);ans^=sg[i];} 72 puts(ans?"Alice":"Bob"); 73 rep(i,1,n) fst[i]=vis[i]=sg[i]=rt[i]=0; 74 } 75 }
T2 bzoj 4731 魔法小程序
题目大意:
现在给出数组$c$ 求数组$b$
思路:
相当于对每个数拆成一个K维空间的点 每一维长度不一样 数组$a$代表每一维的长度
$c_i$为这个K维空间内第i个点所对应多维立方体内的点权和(相当于前缀和
因为一共只有m个点 所以有意义且长度大于1的点不超过$log space m$个
因此我们可以暴力把这些维数还原回去
对于每一维 我们从m-1枚举到0 可以减去次一维的立方体的影响
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #define rep(i,s,t) for(register int i=(s);i<=(t);++i) 11 #define dwn(i,s,t) for(register int i=(s);i>=(t);--i) 12 #define ren for(int i=fst[x];i;i=nxt[i]) 13 #define Fill(x,t) memset(x,t,sizeof(x)) 14 #define ll long long 15 #define inf 2139062143 16 #define MAXN 1001000 17 using namespace std; 18 inline ll read() 19 { 20 ll x=0,f=1;char ch=getchar(); 21 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 22 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 23 return x*f; 24 } 25 ll n,m,a[MAXN],c[MAXN],mul[MAXN]; 26 int main() 27 { 28 n=read();printf("%d ",n);rep(i,0,n-1) {a[i]=read();printf("%lld ",a[i]);if(a[i]==1) n--,i--;} 29 m=read();rep(i,0,m-1) c[i]=read();mul[0]=1,a[n++]=inf;int x,y; 30 rep(i,1,n-1) {mul[i]=mul[i-1]*a[i-1];if(mul[i]>m) {n=i;break;}} 31 rep(i,0,n-1) 32 { 33 x=m%mul[i],y=(m/mul[i])%a[i]; 34 dwn(j,m-1,0) {if(x) x--;else x=mul[i]-1,y=y?y-1:a[i]-1;if(y) c[j]-=c[j-mul[i]];} 35 } 36 printf(" %d ",m); 37 rep(i,0,m-1) printf("%lld ",c[i]); 38 }
bzoj 4732 数据交互
这道ddp并不可做(因为甚至没学ddp 有机会再回来
发现了这题的树剖做法非常强
题目大意:
每次可以对一个链安排或删除一个权值使这个链上的点都具有这个权值
每次求一个权值和最大的链(同时被安排的权值只能算一次)
思路:
由于每一次修改的在统计时只算一次 我们可以考虑维护两个数组表示是否以这个点的lca的路径上该点的权值
设$a_i$表示以$i$点为lca的路径的权值和 $b_i$表示经过$i$点且lca不为$i$的路径的权值和
对于每条路径答案即为$b_{lca} + sum_{x in path} a_x $
同时 一条路径也一定可以分为重链$(u,v),(dep_u le dep_v)$ ; ($v - $ 轻儿子);轻儿子再引出的重链
因此对于全局权值和最大的链 用线段树来维护每条重链的答案 相当于维护最大连续和
对于每一个点开一个可删堆来维护它最大的轻儿子子链
每次修改的时候 对于这条链 改动b数组 区间修改沿途的重链的答案(只修改最大后缀因为沿途的答案为后缀
当达到lca时 继续向上走 单点修改每个点的答案(修改每个新进入重链的点的最大前后缀为经过轻儿子的堆顶,最大值为经过轻儿子的两个堆顶和)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 11 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 12 #define ren for(register int i=fst[x];i;i=nxt[i]) 13 #define Fill(x,t) memset(x,t,sizeof(x)) 14 #define ll long long 15 #define inf 2139062143 16 #define MAXN 100100 17 using namespace std; 18 inline int read() 19 { 20 int x=0,f=1;char ch=getchar(); 21 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 22 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 23 return x*f; 24 } 25 int n,m,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],cnt,tot; 26 int fa[MAXN],dep[MAXN],bl[MAXN],hvs[MAXN],sz[MAXN],dfn[MAXN],lfs[MAXN]; 27 int qu[MAXN],qv[MAXN],qw[MAXN]; 28 struct node{ll sum,mx,lm,rm,tag;}tr[MAXN<<2]; 29 struct Heap 30 { 31 priority_queue<ll> A,B; 32 void push(ll x) {A.push(x);} 33 ll top() {while(!B.empty()&&A.top()==B.top()) A.pop(),B.pop();return A.top();} 34 void pop(ll x) {B.push(x);} 35 }q[MAXN],ans; 36 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 37 void dfs(int x,int pa) 38 { 39 fa[x]=pa,dep[x]=dep[pa]+1,sz[x]=1; 40 ren if(to[i]!=pa) {dfs(to[i],x);sz[x]+=sz[to[i]];if(sz[to[i]]>sz[hvs[x]]) hvs[x]=to[i];} 41 } 42 void Dfs(int x,int anc) 43 { 44 bl[x]=anc,dfn[x]=++tot,lfs[x]=x;if(!hvs[x]) return ;Dfs(hvs[x],anc); 45 lfs[x]=lfs[hvs[x]];ren if(to[i]!=fa[x]&&to[i]!=hvs[x]) Dfs(to[i],to[i]); 46 } 47 void pshd(int k,node &a,node &b,ll x=0) {x=tr[k].tag,a.tag+=x,b.tag+=x,a.rm+=x,b.rm+=x,a.mx+=x,b.mx+=x,tr[k].tag=0;} 48 node upd(node a,node b,int x) {return (node){a.sum+b.sum,max(max(a.mx,b.mx),a.rm+b.lm),max(a.lm,a.sum+b.lm),max(b.rm,b.sum+a.rm),x};} 49 void Mdf(int k,int l,int r,int x,ll a,ll b,ll c) 50 { 51 if(l==r) {tr[k].lm+=a+c,tr[k].rm+=a+c,tr[k].mx+=b+c,tr[k].sum+=c;return ;} 52 int mid=(l+r)>>1;if(tr[k].tag) pshd(k,tr[k<<1],tr[k<<1|1]); 53 if(x<=mid) Mdf(k<<1,l,mid,x,a,b,c);else Mdf(k<<1|1,mid+1,r,x,a,b,c); 54 tr[k]=upd(tr[k<<1],tr[k<<1|1],0LL); 55 } 56 void mdf(int k,int l,int r,int a,int b,ll w) 57 { 58 if(l==a&&r==b) {tr[k].mx+=w,tr[k].rm+=w,tr[k].tag+=w;return ;} 59 int mid=(l+r)>>1;if(tr[k].tag) pshd(k,tr[k<<1],tr[k<<1|1]); 60 if(b<=mid) mdf(k<<1,l,mid,a,b,w); 61 else if(a>mid) mdf(k<<1|1,mid+1,r,a,b,w); 62 else {mdf(k<<1,l,mid,a,mid,w);mdf(k<<1|1,mid+1,r,mid+1,b,w);} 63 tr[k]=upd(tr[k<<1],tr[k<<1|1],0LL); 64 } 65 node query(int k,int l,int r,int a,int b) 66 { 67 if(l>r) return (node){0,0,0,0,0};if(l==a&&r==b) return tr[k]; 68 int mid=(l+r)>>1;if(tr[k].tag) pshd(k,tr[k<<1],tr[k<<1|1]); 69 if(b<=mid) return query(k<<1,l,mid,a,b); 70 else if(a>mid) return query(k<<1|1,mid+1,r,a,b); 71 else return upd(query(k<<1,l,mid,a,mid),query(k<<1|1,mid+1,r,mid+1,b),0LL); 72 } 73 ll calc(int x) {ll res=0,tmp;res=tmp=q[x].top();q[x].pop(tmp);res+=q[x].top();q[x].push(tmp);return res;} 74 void work(int x,int y,int w) 75 { 76 while(bl[x]!=bl[y]) 77 { 78 if(dep[bl[x]]<dep[bl[y]]) swap(x,y); 79 ans.pop(query(1,1,n,dfn[bl[x]],dfn[lfs[x]]).mx);mdf(1,1,n,dfn[bl[x]],dfn[x],w); 80 ans.push(query(1,1,n,dfn[bl[x]],dfn[lfs[x]]).mx);x=fa[bl[x]]; 81 } 82 if(dep[x]>dep[y]) swap(x,y);node p;ll a=0LL,b=0LL; 83 if(x!=y) 84 { 85 ans.pop(query(1,1,n,dfn[bl[x]],dfn[lfs[x]]).mx);mdf(1,1,n,dfn[x]+1,dfn[y],w); 86 ans.push(query(1,1,n,dfn[bl[x]],dfn[lfs[x]]).mx); 87 } 88 while(x) 89 { 90 p=query(1,1,n,dfn[bl[x]],dfn[lfs[x]]);Mdf(1,1,n,dfn[x],b,a,w); 91 a=-calc(fa[bl[x]]),b=-q[fa[bl[x]]].top(),w=0LL; 92 ans.pop(p.mx);q[fa[bl[x]]].pop(p.lm); 93 p=query(1,1,n,dfn[bl[x]],dfn[lfs[x]]);ans.push(p.mx);q[fa[bl[x]]].push(p.lm); 94 a+=calc(fa[bl[x]]),b+=q[fa[bl[x]]].top(),x=fa[bl[x]]; 95 } 96 } 97 int main() 98 { 99 n=read(),m=read();int a,b,c;char ch[3];rep(i,0,n<<1|1) q[i>>1].push(0LL);ans.push(0LL);ans.push(0LL); 100 rep(i,2,n) {a=read(),b=read();add(a,b);add(b,a);}dfs(1,0);Dfs(1,1); 101 rep(i,1,m) 102 { 103 scanf("%s",ch); 104 if(ch[0]=='+') {qu[i]=read(),qv[i]=read(),qw[i]=read();work(qu[i],qv[i],qw[i]);} 105 else {a=read();work(qu[a],qv[a],-qw[a]);} 106 printf("%lld ",ans.top()); 107 } 108 }