• 【XSY2665】没有上司的舞会 LCT DP


    题目大意

      有一棵树,最开始只有一个点。每次会往这棵树中加一个点,总共(n)次。输出每次加点后树的最大独立集大小。

      强制在线。

      (nleq 300000)

    题解

      显然是LCT。

      那么要维护什么呢?

      先看看DP方程:设(f_{i,0})为以(i)为根的子树中(i)这个点不选的答案,(f_{i,1})(i)这个点选的答案。显然

    [egin{align} f_{i,0}&=sum_{v}max(f_{v,0},f_{v,1})\ f_{i,1}&=1+sum_v f_{v,0} end{align} ]

      先看看一条链要怎么做。设(s_{i,j})为某一段中第一个点的状态为(i),在后面补一个状态为(j)的点时这一段的贡献。这个东西很容易合并。

      只有一个点时

    [egin{align} s_{0,0}&=0\ s_{0,1}&=0\ s_{1,0}&=1\ s_{1,1}&=-infty end{align} ]

      那树上要怎么做?

      容易观察到(i)的各个儿子之间是互不影响的。可以像这道题一样,把整棵树剖成轻重链,每个点的贡献要加上这个点的轻儿子的贡献。

      access和link时处理一下即可。

      时间复杂度:(O(nlog n))

    题解

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<cmath>
    #include<functional>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> pll;
    void sort(int &a,int &b)
    {
    	if(a>b)
    		swap(a,b);
    }
    void open(const char *s)
    {
    #ifndef ONLINE_JUDGE
    	char str[100];
    	sprintf(str,"%s.in",s);
    	freopen(str,"r",stdin);
    	sprintf(str,"%s.out",s);
    	freopen(str,"w",stdout);
    #endif
    }
    int rd()
    {
    	int s=0,c;
    	while((c=getchar())<'0'||c>'9');
    	do
    	{
    		s=s*10+c-'0';
    	}
    	while((c=getchar())>='0'&&c<='9');
    	return s;
    }
    void put(int x)
    {
    	if(!x)
    	{
    		putchar('0');
    		return;
    	}
    	static int c[20];
    	int t=0;
    	while(x)
    	{
    		c[++t]=x%10;
    		x/=10;
    	}
    	while(t)
    		putchar(c[t--]+'0');
    }
    int upmin(int &a,int b)
    {
    	if(b<a)
    	{
    		a=b;
    		return 1;
    	}
    	return 0;
    }
    int upmax(int &a,int b)
    {
    	if(b>a)
    	{
    		a=b;
    		return 1;
    	}
    	return 0;
    }
    struct p
    {
    	ll s11,s12,s21,s22;
    	p()
    	{
    		s11=s12=s21=s22=0;
    	}
    };
    p merge(p a,p b)
    {
    	p c;
    	c.s11=max(a.s11+b.s11,a.s12+b.s21);
    	c.s12=max(a.s11+b.s12,a.s12+b.s22);
    	c.s21=max(a.s21+b.s11,a.s22+b.s21);
    	c.s22=max(a.s21+b.s12,a.s22+b.s22);
    	return c;
    }
    void add(p &a,ll s11,ll s12,ll s21,ll s22)
    {
    	a.s11+=s11;
    	a.s12+=s12;
    	a.s21+=s21;
    	a.s22+=s22;
    }
    namespace lct
    {
    	int f[300010];
    	int a[300010][2];
    	p v[300010];
    	p s[300010];
    	int root(int x)
    	{
    		return !f[x]||(a[f[x]][0]!=x&&a[f[x]][1]!=x);
    	}
    	void mt(int x)
    	{
    		s[x]=v[x];
    		if(a[x][0])
    			s[x]=merge(s[a[x][0]],s[x]);
    		if(a[x][1])
    			s[x]=merge(s[x],s[a[x][1]]);
    	}
    	void rotate(int x)
    	{
    		int p=f[x];
    		int q=f[p];
    		int ps=(x==a[p][1]);
    		int qs=(p==a[q][1]);
    		int ch=a[x][ps^1];
    		if(!root(p))
    			a[q][qs]=x;
    		a[x][ps^1]=p;
    		a[p][ps]=ch;
    		if(ch)
    			f[ch]=p;
    		f[p]=x;
    		f[x]=q;
    		mt(p);
    	}
    	void splay(int x)
    	{
    		while(!root(x))
    		{
    			int p=f[x];
    			if(!root(p))
    			{
    				int q=f[p];
    				if((p==a[q][1])==(x==a[p][1]))
    					rotate(p);
    				else
    					rotate(x);
    			}
    			rotate(x);
    		}
    		mt(x);
    	}
    	void access(int x)
    	{
    		int y=x;
    		int t=0;
    		while(x)
    		{
    			splay(x);
    			add(v[x],max(s[a[x][1]].s21,s[a[x][1]].s22),max(s[a[x][1]].s21,s[a[x][1]].s22),max(max(s[a[x][1]].s11,s[a[x][1]].s12),max(s[a[x][1]].s21,s[a[x][1]].s22)),max(max(s[a[x][1]].s11,s[a[x][1]].s12),max(s[a[x][1]].s21,s[a[x][1]].s22)));
    			add(v[x],-max(s[t].s21,s[t].s22),-max(s[t].s21,s[t].s22),-max(max(s[t].s11,s[t].s12),max(s[t].s21,s[t].s22)),-max(max(s[t].s11,s[t].s12),max(s[t].s21,s[t].s22)));
    			a[x][1]=t;
    			mt(x);
    			t=x;
    			x=f[x];
    		}
    		splay(y);
    	}
    	void link(int x,int y)
    	{
    		v[x].s11=-0x7fffffff;
    		v[x].s12=1;
    		v[x].s21=0;
    		v[x].s22=0;
    		mt(x);
    		access(y);
    		f[x]=y;
    		a[y][1]=x;
    //		add(v[y],1,0);
    		mt(y);
    	}
    };
    int main()
    {
    	open("b");
    	int n,type;
    	scanf("%d%d",&n,&type);
    	int i,x;
    	int ans=0;
    	lct::v[1].s11=-0x7fffffff;
    	lct::v[1].s12=1;
    	lct::v[1].s21=0;
    	lct::v[1].s22=0;
    	lct::mt(1);
    	for(i=2;i<=n+1;i++)
    	{
    		scanf("%d",&x);
    		if(type)
    			x^=ans;
    		x++;
    		lct::link(i,x);
    		lct::access(1);
    		ans=max(max(lct::s[1].s11,lct::s[1].s21),max(lct::s[1].s12,lct::s[1].s22));
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux消息队列相关操作
    linux下删除3分钟之前指定文件夹下的指定类型文件
    centos6.5安装gmime-2.6
    centos6.5安装filezilla
    posix 正则库程序
    nginx正向vs反向代理
    AbstractQueuedSynchronizer 原理分析
    JAVA NIO详解
    java NIO原理及实例
    Thread类详解
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8513335.html
Copyright © 2020-2023  润新知