zoukankan      html  css  js  c++  java
  • BZOJ4911: [Sdoi2017]切树游戏

    BZOJ 4911 切树游戏

    重构了三次.jpg

    每次都把这个问题想简单了.jpg

    果然我还是太菜了.jpg

    这种题的题解可以一眼秒掉了,FWT+动态DP简直是裸的一批...

    那么接下来,考虑如何维护信息。

    每个点维护$4$个信息,分别表示,这条链自底向上,自上向底,两端都在这条链的轻儿子里,和两端为链头的方案数。

    这样的话,正常询问就没啥问题了,只需要每次修改和初始化的时候FWT一下,然后最后FWT回来即可。

    然后这样做的话,因为FWT没有可减性(没法求逆),所以每次需要将轻儿子用线段树维护一下,然后每次重建即可

    (是我菜了,FWT之间求每个对应位置的逆元然后乘起来就行...

    剩下的就是DDP正常操作了...

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    #include <bitset>
    using namespace std;
    #define N 30005
    #define M 128
    #define mod 10007
    #define inv2 5004
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    int n,m,Q,a[N];
    struct node{int to,next;}e[N<<1];
    int head[N],cnt,fa[N],anc[N],son[N],siz[N],idx[N],tims,p[N],sson[N];
    // ploy
    struct Ploy
    {
    	int a[M],len;
    	void FWT(int opt)
    	{
    		for(int k=2,tmp;k<=m;k<<=1)
    			for(int i=0,t=k>>1;i<m;i+=k)
    				for(int j=i;j<i+t;j++)
    					if(opt==1)tmp=a[j],a[j]=(a[j]+a[j+t])%mod,a[j+t]=(mod+tmp-a[j+t])%mod;
    					else tmp=a[j],a[j]=(a[j]+a[j+t])*inv2%mod,a[j+t]=(mod+tmp-a[j+t])*inv2%mod;
    	}
    	Ploy(){}
    	Ploy(int x){len=1;a[0]=x;FWT(1);}
    	Ploy(int p,int x){memset(a,0,sizeof(a));len=m;a[p]=x;FWT(1);}
    	Ploy(int *b,int m){memcpy(a,b,sizeof(a));len=m;}
    	Ploy operator + (const Ploy &b) const
    	{
    		Ploy c;c.len=max(b.len,len);
    		for(int i=0;i<c.len;i++)c.a[i]=(a[i]+b.a[i])%mod;
    		return c;
    	}
    	Ploy operator - (const Ploy &b) const
    	{
    		Ploy c;c.len=max(b.len,len);
    		for(int i=0;i<c.len;i++)c.a[i]=(mod+a[i]-b.a[i])%mod;
    		return c;
    	}
    	Ploy operator * (const Ploy &b) const
    	{
    		Ploy c;c.len=max(b.len,len);
    		for(int i=0;i<c.len;i++)c.a[i]=a[i]*b.a[i]%mod;
    		return c;
    	}
    	int get(int x){FWT(-1);return a[x];}
    	void print(){FWT(-1);for(int i=0;i<m;i++)printf("%d ",a[i]);puts("");FWT(1);}
    }f[N],g[N],s[N],h[N],one,tmp,A[N];
    // Segment_Tree of all the sons
    vector<Ploy>Tr[N];
    vector<int>lsn[N];
    int pos[N];
    void build(int x,int l,int r,int rt)
    {
    	if(l==r){Tr[x][rt]=f[lsn[x][l-1]]+one;pos[lsn[x][l-1]]=rt;return ;}
    	int m=(l+r)>>1;build(x,lson);build(x,rson);Tr[x][rt]=Tr[x][rt<<1]*Tr[x][rt<<1|1];
    }
    
    // Segment_Tree of DDP
    struct Segment
    {
    	Ploy a,b,c,d;
    	Segment(){}
    	Segment(Ploy x,Ploy y){a=b=c=x;d=x+y;}
    	Segment operator + (const Segment &A) const
    	{
    		Segment B;
    		B.a=a*A.a;
    		B.b=b+A.b*a;
    		B.c=A.c+A.a*c;
    		B.d=d+A.d+A.b*c;
    		return B;
    	}
    }tr[N<<2];
    void build(int l,int r,int rt)
    {
    	if(l==r){tr[rt]=Segment(A[p[l]]*g[p[l]],s[p[l]]);return ;}
    	int m=(l+r)>>1;build(lson);build(rson);tr[rt]=tr[rt<<1]+tr[rt<<1|1];
    }
    Segment query(int L,int R,int l,int r,int rt)
    {
    	if(L<=l&&r<=R)return tr[rt];int m=(l+r)>>1;
    	if(R<=m)return query(L,R,lson);if(L>m)return query(L,R,rson);
    	return query(L,R,lson)+query(L,R,rson);
    }
    void Update(int x,int l,int r,int rt)
    {
    	if(l==r){tr[rt]=Segment(A[p[l]]*g[p[l]],s[p[l]]);return ;}
    	int m=(l+r)>>1;if(x<=m)Update(x,lson);else Update(x,rson);tr[rt]=tr[rt<<1]+tr[rt<<1|1];
    }
    void Update(int x)
    {
    	Segment tmp=Segment();
    	while(x)
    	{
    		Update(idx[x],1,n,1);x=anc[x];
    		if(fa[x])
    		{
    			tmp=query(idx[x],idx[sson[x]],1,n,1);
    			s[fa[x]]=s[fa[x]]-h[x]+tmp.d;f[x]=tmp.b;
    			h[x]=tmp.d;int rt=pos[x];Tr[fa[x]][rt]=f[x]+one;
    			for(rt>>=1;rt;rt>>=1)Tr[fa[x]][rt]=Tr[fa[x]][rt<<1]*Tr[fa[x]][rt<<1|1];
    			g[fa[x]]=Tr[fa[x]][1];
    		}x=fa[x];
    	}
    }
    // Graph
    void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;}
    void dfs1(int x,int from)
    {
    	fa[x]=from;siz[x]=1;f[x]=A[x];
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(to1!=from)dfs1(to1,x),f[x]=f[x]*(f[to1]+one),h[x]=h[x]+h[to1],siz[x]+=siz[to1],siz[son[x]]<siz[to1]?son[x]=to1:0;
    	}h[x]=h[x]+f[x];
    }
    void dfs2(int x,int top)
    {
    	anc[x]=top;idx[x]=++tims;p[tims]=x;sson[x]=x;g[x]=one;
    	if(son[x])dfs2(son[x],top),sson[x]=sson[son[x]];
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(to1!=son[x]&&to1!=fa[x])dfs2(to1,to1),g[x]=g[x]*(f[to1]+one),s[x]=s[x]+h[to1],lsn[x].push_back(to1);
    	}
    	if(!lsn[x].size())return ;
    	Tr[x].resize(lsn[x].size()*4+5);
    	build(x,1,lsn[x].size(),1);
    }
    
    char opt[10];
    int main()
    {
    	int size = 0x8000000; 
    	char*p=(char*)malloc(size) + size;
    	__asm__("movl %0, %%esp
    " :: "r"(p) );
    	scanf("%d%d",&n,&m);memset(head,-1,sizeof(head));
    	one.a[0]=1;one.len=1;one.FWT(1);
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]),A[i]=Ploy(a[i],1);
    	for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
    	dfs1(1,0);dfs2(1,1);build(1,n,1);scanf("%d",&Q);
    	while(Q--)
    	{
    		int x,y;scanf("%s%d",opt,&x);
    		if(opt[0]=='Q')tmp=query(idx[1],idx[sson[1]],1,n,1).d,printf("%d
    ",tmp.get(x));
    		else
    		{
    			scanf("%d",&y);a[x]=y;A[x]=Ploy(a[x],1);
    			Update(x);
    		}
    	}
    }
    
  • 相关阅读:
    EZchip花1.3亿美元买Tilera然后以8亿美元把自己与Tilera一起卖掉
    [OFC]Mellanox发布首个200Gb/s硅光子设备
    Mellanox 8亿美元收购EZchip
    EZchip将推全球首款100核64位ARM A-53芯片
    MyBatis映射文件5
    MyBatis映射文件4(参数获取#{}和${}/select标签详解[返回类型为list])
    MyBatis源码分析1 参数映射分析
    MyBatis映射文件3(参数处理Map)
    MyBatis映射文件2(不支持自增的数据库解决方案/参数处理[单参、多参、命名参数])
    MyBatis映射文件1(增删改、insert获取自增主键值)
  • 原文地址:https://www.cnblogs.com/Winniechen/p/10533091.html
Copyright © 2011-2022 走看看