zoukankan      html  css  js  c++  java
  • 天天爱跑♂步

    线段树,枚举,暴力

    写的头皮发麻......

    对于每一次跑动(u,v)显然,我们需要对(u,lca),(lca,v)分别处理。为什么?考虑每个点 i 能得到的贡献,一种是从以它为根的子树跑上来,另一种是路径的终点在它的子树中。第一类:d[s]-d[i]=w[i],得到式子:d[s]=d[i]+w[i]。第二类:T[s,t]=w[i]+d[t]-d[i],得到:T[s,t]-d[t]=w[i]-d[i]。我们需要进行树上区间修改,单点查询,而且还要分深度进行(例如,深度为k的起点能贡献到的点的权值++)所以我们选择按深度建立N*2棵线段树,每个深度有两个线段树,分别维护那两个值。然后就写吧:树剖+lca+线段树+动态开点。

    错误集锦

    1、动态开点线段树记得pushdown时要开好点。
    2、记得去掉对lca的重复贡献。
    3、线段树的点要开的足够多!!

    code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define half (l+r)>>1
    using namespace std;
    const int maxn=600008;
    int head[maxn],cur;
    int n,m,tot[maxn],top[maxn],fa[maxn],d[maxn],son[maxn],id[maxn],fina[maxn];
    int tre,num[maxn],wh[maxn];
    int wow[maxn];
    struct hzw
    {
    	int to,next;
    }e[maxn];
    struct ljm
    {
    	int w;
    	int lc,rc,tag;
    }t[10000006][2];
    inline int read(){
        int out=0,flag=1;char c=getchar();
        while(c<48||c>57) {if(c=='-') flag=-1;c=getchar();}
        while(c>=48&&c<=57){out=out*10+c-48;c=getchar();}
        return out*flag;
    }
    inline void add(int a,int b)
    {
    	e[cur].to=b;
    	e[cur].next=head[a];
    	head[a]=cur++;
    }
    inline void pushdown (int u,int l,int r,int k){
         int mid=half;
         if (!t[u][k].lc) t[u][k].lc=++tre;
         if (!t[u][k].rc) t[u][k].rc=++tre;
         t[t[u][k].lc][k].w+=t[u][k].tag*(mid-l+1);
         t[t[u][k].lc][k].tag+=t[u][k].tag;
         t[t[u][k].rc][k].w+=t[u][k].tag*(r-mid);
         t[t[u][k].rc][k].tag+=t[u][k].tag;
         t[u][k].tag=0;
    }
    
    inline void update(int &s,int l,int r,int ll,int rr,int v,int k)
    {
    	if (!s) s=++tre;
        if (l==ll&&r==rr)
        {
            t[s][k].w+=(r-l+1)*v;
            t[s][k].tag+=v;
            return;
        }
        if (t[s][k].tag) pushdown(s,l,r,k);
        int mid=half;
        if (rr<=mid) update(t[s][k].lc,l,mid,ll,rr,v,k);
        else if (ll>mid) update(t[s][k].rc,mid+1,r,ll,rr,v,k);
        else 
        {
          update(t[s][k].lc,l,mid,ll,mid,v,k);
          update(t[s][k].rc,mid+1,r,mid+1,rr,v,k);
        }
        t[s][k].w=t[t[s][k].lc][k].w+t[t[s][k].rc][k].w;
    }
    inline int query(int s,int l,int r,int cl,int cr,int k)
    {
    	if (!s) return 0;
    	if (l==cl&&r==cr)
    	{
    		return t[s][k].w;
    	}
    	if (t[s][k].tag) pushdown(s,l,r,k);
    	int mid=half;
    	if (cr<=mid)     return query(t[s][k].lc,l,mid,cl,cr,k);
    	else if (cl>mid) return query(t[s][k].rc,mid+1,r,cl,cr,k);
    	else {
    		return query(t[s][k].lc,l,mid,cl,mid,k)+query(t[s][k].rc,mid+1,r,mid+1,cr,k);
    	}
    }
    inline int dfs1(int s,int f,int l)
    {
        d[s]=l;
    	fa[s]=f; 
    	tot[s]=1;
    	int maxs=-23333;
    	for (int i=head[s];i!=-1;i=e[i].next)
    	{
    		if (e[i].to==f) continue;
    		tot[s]+=dfs1(e[i].to,s,l+1);
    		if (tot[e[i].to]>maxs) 
    		{
    			maxs=tot[e[i].to];
    			son[s]=e[i].to;
    		}
    	}
    	return tot[s];
    }
    int cnt=0;
    
    inline void dfs2(int s,int firs)
    {
    	id[s]=++cnt;
    	top[s]=firs;
    	if (!son[s]) return;
    	dfs2(son[s],firs);
    	for (int i=head[s];i!=-1;i=e[i].next)
    	{
    		if (id[e[i].to]) continue;
    		dfs2(e[i].to,e[i].to);
    	}
    }
    
    inline int lca(int x,int y)
    {
    	if (x==y) return x;
        while (top[x]!=top[y])
        {
        	if (d[top[x]]<d[top[y]]) swap(x,y);
        	x=fa[top[x]];
    	}
    	if (d[x]>d[y]) swap(x,y);
    	return x;
    }
    inline void treup(int root,int a,int b,int val,int k)
    {
    	while (top[a]!=top[b])
        { 	
        	int shit=n+root;
            if (d[top[a]]<d[top[b]]) swap(a,b);
            update(shit,1,n,id[top[a]],id[a],val,k);
            a=fa[top[a]];	
        }
        if (d[a]>d[b]) swap(a,b);
        int shit=n+root;
    	update(shit,1,n,id[a],id[b],val,k);
    }
    int main() {
    	cin>>n>>m;
    	tre=3*n;
    	memset(head,-1,sizeof (head));
    	for (int i=1,a,b;i<=n-1; ++i) {
            a=read(),b=read();
            add(a,b);
            add(b,a);
    	}
    	for (int i=1;i<=n;++i) scanf("%d",&wh[i]);
    	dfs1(1,1,1);
    	dfs2(1,1);
    	int x,y;
    	for (int i=1; i<=m; ++i) {
    		x=read(),y=read();
            int tmp=lca(x,y);
            int tim=d[x]-d[tmp]+d[y]-d[tmp];	
            treup(d[x],x,tmp,1,0); 
            treup(tim-d[y],tmp,y,1,1);
            if (d[tmp]+wh[tmp]==d[x]&&wh[tmp]-d[tmp]==tim-d[y]) wow[tmp]++;
    	}
    	for (int i=1;i<=n;++i)
    	{
    		fina[i]+=query(n+d[i]+wh[i],1,n,id[i],id[i],0);
    		fina[i]+=query(wh[i]-d[i]+n,1,n,id[i],id[i],1);	
    		fina[i]-=wow[i];
    	}
    	for (int i=1;i<=n;++i)
    	{
    		printf("%d ",fina[i]);
    	}
    	return 0;
    }
    

    总结:

    遇到神仙题目时一定要先读题,找到信息,然后考虑难点在于什么,可不可以用数据结构维护,简化。

  • 相关阅读:
    POJ1125-Stockbroker Grapevine【Floyd】(模板题)
    Codeforces 862B (二分图染色)
    hdu3047 Zjnu Stadium【带权并查集】
    HDU1532 网络流最大流【EK算法】(模板题)
    hdu 2063 过山车【匈牙利算法】(经典)
    HDU-2066-一个人的旅行 【Dijkstra】
    HDU 3625 Examining the Rooms【第一类斯特灵数】
    HDU4372-Count the Buildings【第一类Stirling数】+【组合数】
    HDU 6114 Chess【逆元+组合数】(组合数模板题)
    HDU1211 密文解锁 【扩展欧几里得】【逆元】
  • 原文地址:https://www.cnblogs.com/bullshit/p/9669326.html
Copyright © 2011-2022 走看看