zoukankan      html  css  js  c++  java
  • [USACO12NOV]Balanced Trees G

    XI.[USACO12NOV]Balanced Trees G

    与上题类似,我们仍然需要分成\(FR\)路径和\(TO\)路径两部分考虑。默认将根归为\(FR\)路径中考虑。

    首先是判断怎样搞才是合法的。关于这个,我们可以用一个pair<int,int>来记录全部匹配完后,剩余的)(的数量,其中first表示)second表示(。我们设\(fr_x\)表示\(FR\)路径的这一匹配结果,而\(to_x\)表示\(TO\)路径。

    则只有first=0\(FR\)路径与second=0\(TO\)路径才是合法的。同时,只有fr[u].second=to[v].first时,两条路径才能匹配。

    然后就是考虑这括号到底套娃了几层了。

    我们令一个\(dpfr_x\)表示\(FR\)路径的套娃数,而\(dpto_x\)表示\(TO\)路径的套娃数。

    我们只考虑\(TO\)路径的套娃数求法——因为\(FR\)路径的求法也类似。

    任意时刻,to[x].second的值,即为路径最后的那个括号所套的层数。因此当to[x].second增加时,\(dpto_x\)要与其取\(\max\)。(不管这个括号最终能不能匹配完——反正括号不能匹配完时最终也是不合法的路径)

    同时,当to[x].second\(0\)时,如果又来一个右括号,前面所有的括号的套娃层数都会加一,故在此时应令dpto_x++

    \(fr\)的求法与其类似。

    最后,我们只需要开一个桶,记录对于所有to[x].first的值,\(dpto_x\)\(\max\)即可。用fr[x].second从桶中匹配即可。

    这题要求的是\(\max\),而其不具有可减性。因此我们正着跑一遍,然后清空桶并倒着跑一遍即可。复杂度\(O(n\log n)\)

    #include<bits/stdc++.h>
    using namespace std;
    int n,ROOT,SZ,sz[100100],msz[100100],dpfr[100100],dpto[100100],buc[100100],mx;
    pair<int,int>fr[100100],to[100100];
    char s[100100];
    vector<int>v[100100];
    bool vis[100100];
    void getsz(int x,int fa){
    	sz[x]=1;
    	for(auto y:v[x])if(!vis[y]&&y!=fa)getsz(y,x),sz[x]+=sz[y];
    }
    void getroot(int x,int fa){
    	sz[x]=1,msz[x]=0;
    	for(auto y:v[x])if(!vis[y]&&y!=fa)getroot(y,x),sz[x]+=sz[y],msz[x]=max(msz[x],sz[y]);
    	msz[x]=max(msz[x],SZ-sz[x]);
    	if(msz[x]<msz[ROOT])ROOT=x;
    }
    void getbra(int x,int fa){
    //	printf("%d:(%d,%d):%d;(%d,%d):%d\n",x,fr[x].first,fr[x].second,dpfr[x],to[x].first,to[x].second,dpto[x]);
    	for(auto y:v[x]){
    		if(vis[y]||y==fa)continue;
    		dpfr[y]=dpfr[x],dpto[y]=dpto[x],fr[y]=fr[x],to[y]=to[x];
    		if(s[y]=='('){
    			if(fr[y].first)fr[y].first--;
    			else fr[y].second++,dpfr[y]++;
    			to[y].second++,dpto[y]=max(dpto[y],to[y].second);
    		}else{
    			if(to[y].second)to[y].second--;
    			else to[y].first++,dpto[y]++;
    			fr[y].first++,dpfr[y]=max(dpfr[y],fr[y].first);
    		}
    		getbra(y,x);
    	}
    }
    void getread(int x,int fa){
    	if(!fr[x].first&&buc[fr[x].second]!=-1)mx=max(mx,max(buc[fr[x].second],dpfr[x]));
    	for(auto y:v[x])if(!vis[y]&&y!=fa)getread(y,x);
    }
    void getwrite(int x,int fa){
    	if(!to[x].second)buc[to[x].first]=max(buc[to[x].first],dpto[x]);
    	for(auto y:v[x])if(!vis[y]&&y!=fa)getwrite(y,x);
    }
    void geterase(int x,int fa){
    	if(!to[x].second)buc[to[x].first]=-1;
    	for(auto y:v[x])if(!vis[y]&&y!=fa)geterase(y,x);
    }
    void calc(int x){
    //	printf("ROOT:%d\n",x);
    	fr[x]=to[x]=make_pair(0,0),dpfr[x]=1,dpto[x]=0;
    	if(s[x]=='(')fr[x].second++;
    	else fr[x].first++;
    	getbra(x,0);
    	buc[0]=0;
    	for(int i=0;i<v[x].size();i++)if(!vis[v[x][i]])getread(v[x][i],x),getwrite(v[x][i],x);
    	geterase(x,0);
    	buc[0]=0;
    	for(int i=int(v[x].size())-1;i>=0;i--)if(!vis[v[x][i]])getread(v[x][i],x),getwrite(v[x][i],x);
    	geterase(x,0);
    }
    void solve(int x){
    	calc(x);
    	getsz(x,0); 
    	vis[x]=true;
    	for(auto y:v[x])if(!vis[y])ROOT=0,SZ=sz[y],getroot(y,0),solve(ROOT);
    }
    int main(){
    	scanf("%d",&n),memset(buc,-1,sizeof(buc));
    	for(int i=2,x;i<=n;i++)scanf("%d",&x),v[x].push_back(i),v[i].push_back(x);
    	for(int i=1;i<=n;i++)scanf("%s",s+i);
    	msz[0]=n+1,SZ=n,getroot(1,0),solve(ROOT);
    	printf("%d\n",mx);
    	return 0;
    }
    

  • 相关阅读:
    spring boot 在SpringMVC中使用Jackson并格式化时间
    MUI 同一个页面初始化多个pullrefresh 下拉刷新/上拉加载组件的问题
    Fixflow引擎解析(五)(内核)
    Fixflow引擎解析(四)(模型)
    Fixflow引擎解析(三)(模型)
    Fixflow引擎解析(二)(模型)
    Fixflow引擎解析(一)(介绍)
    Raspberry Pi 摄像头模块应用程序文档翻译
    js 继承如何让对象instanceof 当前类及父类均返回true?
    zabbix邮件脚本报警
  • 原文地址:https://www.cnblogs.com/Troverld/p/14605828.html
Copyright © 2011-2022 走看看