zoukankan      html  css  js  c++  java
  • 并不对劲的loj2179:p3714:[BJOI2017]树的难题

    题目大意

    有一棵树,(n)((nleq2*10^5))个点,每条边(i)有颜色(w_i),共有(m)((mleq n))种颜色,第(i)种颜色的权值是(c_i)((|c_i|leq10^4))
    定义一条路径的权值是该路径上所有同色段的颜色的权值之和
    给定(l,r),求边数在([l,r])中权值最大的路径的权值

    题解

    将每个点的所有边按颜色排序后,对这棵树进行点分治,每次统计过当前重心的路径
    用线段树统计应该挺板的吧
    有人用单调队列做,然而我不会,先坑着

    代码
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
    #define pii pair<int ,int>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define maxn 200010 
    #define inf 2147483647
    #define ls (u<<1)
    #define rs (u<<1|1)
    #define mi (L+R>>1)
    #define vv(x) v[x][i].se
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(int x)
    {
    	if(x==0){putchar('0'),putchar('
    ');return;}
    	int f=0;char ch[20];
    	if(x<0)putchar('-'),x=-x;
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    	return;
    }
    int n,m,l,r,ans=-inf,wt,sumsiz,mnsz,vis[maxn];
    long long cnt;
    int siz[maxn],c[maxn];
    vector<pii >v[maxn];
    struct tree
    {
    	int tr[maxn<<2],mk[maxn<<2];
    	void pu(int u){tr[u]=max(tr[ls],tr[rs]);}
    	void mark(int u,int k){mk[u]=tr[u]=k;}
    	void pd(int u){if(mk[u]){mark(ls,mk[u]),mark(rs,mk[u]),mk[u]=0;}}
    	void add(int u,int L,int R,int x,int k)
    	{
    		if(x<=L&&R<=x){tr[u]=max(k,tr[u]),mk[u]=0;return;}
    		pd(u);
    		if(x<=mi)add(ls,L,mi,x,k);
    		else add(rs,mi+1,R,x,k);
    		return pu(u);
    	}
    	int ask(int u,int L,int R,int x,int y)
    	{
    		if(y<L||R<x)return -inf;
    		if(x<=L&&R<=y)return tr[u];
    		pd(u);
    		int res=-inf;
    		if(x<=mi)res=ask(ls,L,mi,x,y);
    		if(y>mi)res=max(res,ask(rs,mi+1,R,x,y));
    		return res;
    	}
    }t[2];
    void getwt(int u,int fa)
    {
    	siz[u]=1;int nwmx=0,lim=v[u].size();
    	rep(i,0,lim-1)if(vv(u)!=fa&&!vis[vv(u)])getwt(vv(u),u),siz[u]+=siz[vv(u)],nwmx=max(nwmx,siz[vv(u)]);
    	nwmx=max(nwmx,sumsiz-siz[u]);
    	if(nwmx<mnsz)wt=u,mnsz=nwmx;
    	return;
    }
    void asktr(int u,int fa,int fac,int dep,int num)
    {
    	if(dep>r)return;
    	int lim=v[u].size(),tmp=max(t[0].ask(1,0,n,l-dep,r-dep),t[1].ask(1,0,n,l-dep,r-dep));if(tmp!=-inf)ans=max(ans,tmp+num);
    	rep(i,0,lim-1)if(!vis[vv(u)]&&vv(u)!=fa)asktr(vv(u),u,v[u][i].fi,dep+1,num+(v[u][i].fi==fac?0:c[v[u][i].fi]));
    }
    void addtr(int u,int fa,int fac,int dep,int num,int f)
    {
    	if(dep>r)return;
    	int lim=v[u].size();t[f].add(1,0,n,dep,num);
    	rep(i,0,lim-1)if(!vis[vv(u)]&&vv(u)!=fa)addtr(vv(u),u,v[u][i].fi,dep+1,num+(v[u][i].fi==fac?0:c[v[u][i].fi]),f);
    }
    void getans(int u,int nowsiz)
    {
    	sumsiz=nowsiz,mnsz=n+1,getwt(u,0);int now=wt;
    	int lim=v[now].size(),p=0;t[0].mark(1,-inf),t[1].mark(1,-inf);t[0].add(1,0,n,0,0);
    	cnt+=(long long)nowsiz;
    	rep(i,0,lim-1)
    	{
    		if(!vis[vv(now)])
    		{
    			asktr(vv(now),now,v[now][i].fi,1,c[v[now][i].fi]),
    			addtr(vv(now),now,v[now][i].fi,1,0,1);
    		}
    		if(i!=lim-1&&v[now][i].fi!=v[now][i+1].fi)
    		{
    			rep(j,p,i)if(!vis[v[now][j].se])addtr(v[now][j].se,now,v[now][j].fi,1,c[v[now][j].fi],0);
    			t[1].mark(1,-inf);
    			p=i+1;
    		}
    	}
    	vis[now]=1;
    	rep(i,0,lim-1)if(!vis[vv(now)])getans(vv(now),siz[vv(now)]>siz[now]?nowsiz-siz[now]:siz[vv(now)]);
    	return;
    }
    int main()
    {
    	n=read(),m=read(),l=read(),r=read();if(l<=0&&0<=r)ans=0;
    	rep(i,1,m)c[i]=read();
    	rep(i,1,n-1){int x=read(),y=read(),z=read();v[x].pb(mp(z,y)),v[y].pb(mp(z,x));}
    	rep(i,1,n)sort(v[i].begin(),v[i].end());
    	getans(1,n);
    	write(ans);
    	return 0;
    }
    /*
    5 3 1 4
    -1 -5 -2
    1 2 1
    1 3 1
    2 4 2
    2 5 3
    */
    /*
    8 4 3 4
    -7 9 6 1
    1 2 1
    1 3 2
    1 4 1
    2 5 1
    5 6 2
    3 7 1
    3 8 3
    */
    
  • 相关阅读:
    多重背包POJ1276不要求恰好装满 poj1014多重背包恰好装满
    哈理工1053完全背包
    求最小公倍数与最大公约数的函数
    Bus Pass ZOJ 2913 BFS 最大中取最小的
    POJ 3624 charm bracelet 01背包 不要求装满
    HavelHakimi定理(判断一个序列是否可图)
    z0j1008Gnome Tetravex
    ZOJ 1136 Multiple BFS 取模 POJ 1465
    01背包 擎天柱 恰好装满 zjut(浙江工业大学OJ) 1355
    zoj 2412 水田灌溉,求连通分支个数
  • 原文地址:https://www.cnblogs.com/xzyf/p/10455146.html
Copyright © 2011-2022 走看看