• 【51nod 2004】终结之时


    题目大意

    “将世界终结前最后的画面,深深刻印进死水般的心海.”
    祈愿没有得到回应,雷声冲破云霄,正在祈愿的洛天依受到了极大的打击。
    洛天依叹了口气,说:”看来这个世界正如我之前所说的一样,早已失去一切生机”
    你沉默了下来,没有说什么话,只是静静地坐在洛天依的身旁,一同观赏这末日之景.
    天空被云朵覆盖,一朵具有强大能量的云映入你们的眼帘,这是始云!是抽取世界能量的最重要的一朵云!但是洛天依明显没有破坏这朵云的斗志了,你也只好静静地观赏.
    这个世界被吸取的能量从始云开始传递,通过愿银线输送到各个积雨云上,每朵积雨云即作为能量中转点,又作为能量湮灭点。如此,整片天空构成了一个巨大的能量输送网络。很巧,我们可以用图论中的有向图来描述这个网络.
    我们定义始云的编号为1.
    对于一朵积雨云y,如果从始云开始到这个点的所有路径都经过了点x,那么我们称x是y的支配云,x支配y,y被x支配。显然一个点的支配云可能有多个且至少有两个。
    旁边的洛天依此时非常惊讶,因为她发现不同的积雨云的能量强度不一样!
    洛天依用正整数来描述这个能量的强度,同时起名为湮灭能量数.
    也就是说在这个云朵湮灭的能量的单位数目.
    然而整个网络中的云湮灭的能量数在不断的变化中,变化的情况如下:
    C 1 u w有一股能量在云朵u中湮灭了w的能量.
    C 2 u w点u支配的所有云朵上都湮灭了w能量
    C 3 u w支配点u的所有的云朵上都湮灭了w的能量
    “最后一次求你了,为我推演一下这毁灭能量的变化吧.”
    洛天依一共有四种请求:
    Q 1 u 询问u支配的所有的云朵的湮灭能量数之和.
    Q 2 u 询问支配u的所有的云朵的湮灭能量数权值之和.
    Q 3 s x1 x2 ... xs 询问所有支配了其中任一云朵的云朵的湮灭能量数权值之和.
    R k让状态回到k次变化之前.若k大于已经执行的操作数,则视为回到初始状态.
    你自然不忍心拒绝洛天依,于是你打算圆满完成这个任务.

    分析

    支配树裸题,
    先构出支配树,然后树链剖分。
    经典的树链剖分操作。

    注:目前我还没有打关于支配树的介绍,因为我还不是理解透彻,本月内我将会打一篇支配树的blog。

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <bitset>
    #include <set>
    #include <vector>
    #define clear(a) memset(a,0,sizeof(a))
    const int inf=2147483647;
    const int mo=1e9+7;
    const int N=100005;
    using namespace std;
    int head[N], pre[N], dom[N], to[N*20], nt[N*20], tot,lt[N],w[N];
    void link(int *h,int fr,int tt)
    {
    	tot ++;
    	nt[tot] = h[fr];
    	to[tot] = tt;
    	h[fr] = tot;
    }
    int n, m;
    void init()
    {
    	scanf("%d%d", &n, &m);
    	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    	int a, b;
    	for(int i = 1; i <= m; ++i)
    	{
    		scanf("%d%d", &a, &b);
    		link(head, a, b);
    		link(pre, b, a);
    	}
    }
    int bcj[N], semi[N], idom[N], best[N], dfn[N], id[N], fa[N], num;
    int push(int v)
    {
    	if(v == bcj[v]) return v;
    	int y = push(bcj[v]);
    	if(dfn[semi[best[bcj[v]]]] < dfn[semi[best[v]]]) best[v] = best[bcj[v]];
    	return bcj[v] = y;
    }
    void dfs(int rt)
    {
    	dfn[rt] = ++num;
    	id[num] = rt;
    	for(int i = head[rt]; i; i = nt[i])
    		if(!dfn[to[i]])
    		{
    			dfs(to[i]);
    			fa[to[i]] = rt;
    		}
    
    }
    void tarjan()
    {
    	for(int i = n, u; i >= 2; --i)
    	{
    		u = id[i];
    		for(int j = pre[u]; j; j = nt[j])
    		{
    			if(!dfn[to[j]]) continue;
    			push(to[j]);
    			if(dfn[semi[best[to[j]]]] < dfn[semi[u]]) semi[u] = semi[best[to[j]]];
    		}
    		link(dom, semi[u], u);
    		bcj[u] = fa[u];u = id[i - 1];
    		for(int j = dom[u]; j; j = nt[j])
    		{
    			push(to[j]);
    			if(semi[best[to[j]]] == u) idom[to[j]] = u;
    			else idom[to[j]] = best[to[j]];
    		}
    	}
    	for(int i = 2, u; i <= n; ++i)
    	{
    		u = id[i];
    		if(idom[u] != semi[u]) idom[u] = idom[idom[u]];
    		link(lt,idom[u],u);
    	}
    }
    int son[N],size[N],deep[N],top[N],en[N];
    void dg(int x)
    {
    	deep[x]=deep[fa[x]]+1;
    	size[x]=1;
    	for(int i=lt[x];i;i=nt[i])
    	{
    		int j=to[i];
    		if(j==fa[x]) continue;
    		fa[j]=x;
    		dg(j);
    		size[x]+=size[j];
    		if(size[j]>size[son[x]]) son[x]=j;
    	}
    }
    void dg1(int x)
    {
    	id[++num]=x,dfn[x]=num;
    	if(!top[x]) top[x]=x;
    	if(son[x]) top[son[x]]=top[x],dg1(son[x]);
    	for(int i=lt[x];i;i=nt[i])
    	{
    		int j=to[i];
    		if(j==fa[x] || j==son[x]) continue;
    		dg1(j);
    	}
    	en[x]=num;
    }
    struct tree
    {
    	long long s,la,l,r;
    }tr[N*30];
    int rt[N];
    void newp(int v)
    {
    	tr[++num]=tr[tr[v].l],tr[v].l=num;
    	tr[++num]=tr[tr[v].r],tr[v].r=num;
    }
    void down(int v,int l,int r,int mid)
    {
    	if(!tr[v].la) return;
    	newp(v);
    	tr[tr[v].l].s+=tr[v].la*(mid-l+1);
    	tr[tr[v].r].s+=tr[v].la*(r-mid);
    	tr[tr[v].l].la+=tr[v].la,tr[tr[v].r].la+=tr[v].la;
    	tr[v].la=0;
    	return;
    }
    void put(int v,int l,int r,int x,int y,int z)
    {
    	if(l==x && y==r)
    	{
    		tr[v].s+=z*(r-l+1),tr[v].la+=z;
    		return;
    	}
    	int mid=(l+r)>>1;
    	down(v,l,r,mid);
    	if(y<=mid) tr[++num]=tr[tr[v].l],tr[v].l=num,put(tr[v].l,l,mid,x,y,z);
    	else
    	if(x>mid) tr[++num]=tr[tr[v].r],tr[v].r=num,put(tr[v].r,mid+1,r,x,y,z);
    	else
    		tr[++num]=tr[tr[v].l],tr[v].l=num,tr[++num]=tr[tr[v].r],tr[v].r=num,
    		put(tr[v].l,l,mid,x,mid,z),put(tr[v].r,mid+1,r,mid+1,y,z);
    	tr[v].s=tr[tr[v].l].s+tr[tr[v].r].s;
    }
    long long find(int v,int l,int r,int x,int y)
    {
    	if(l==x && y==r) return tr[v].s;
    	int mid=(l+r)>>1;
    	down(v,l,r,mid);
    	if(y<=mid) return find(tr[v].l,l,mid,x,y);
    	else
    	if(x>mid) return find(tr[v].r,mid+1,r,x,y);
    	else
    		return find(tr[v].l,l,mid,x,mid)+find(tr[v].r,mid+1,r,mid+1,y);
    }
    void up(int v,int x,int y)
    {
    	for(;x;x=fa[top[x]]) put(v,1,n,dfn[top[x]],dfn[x],y);
    }
    long long up1(int v,int x)
    {
    	long long ans=0;
    	for(;x;x=fa[top[x]]) ans+=find(v,1,n,dfn[top[x]],dfn[x]);
    	return ans;
    }
    int st[N];
    bool cmp(int x,int y)
    {
    	return dfn[x]<dfn[y];
    }
    int lca(int u,int v)
    {
    	int f1=top[u],f2=top[v];
    	while(f1!=f2)
    	{
    		if(deep[f1]<deep[f2]) swap(f1,f2),swap(u,v);
    		u=fa[f1],f1=top[u];
    	}
    	if(deep[u]>deep[v]) swap(u,v);
    	return u;
    }
    int main()
    {
    	init();
    	for(int i=1;i<=n;i++) bcj[i]=semi[i]=best[i]=i;
    	dfs(1),tarjan();
    	num=0;
    	clear(fa),clear(dfn),clear(id);
    	dg(1),dg1(1);
    	rt[0]=num=1;
    	for(int i=1;i<=n;i++) put(rt[0],1,n,dfn[i],dfn[i],w[i]);
    	scanf("%d",&m);
    	for(int x,y,t,now=0;m--;)
    	{
    		char ch=getchar();
    		for(;ch!='C' && ch!='Q' && ch!='R';) ch=getchar();
    		if(ch=='C')
    		{
    			scanf("%d%d%d",&t,&x,&y);
    			rt[++now]=++num,tr[rt[now]]=tr[rt[now-1]];
    			if(t==1) put(rt[now],1,n,dfn[x],dfn[x],y);
    			else
    			if(t==2) put(rt[now],1,n,dfn[x],en[x],y);
    			else up(rt[now],x,y);
    		}
    		else
    		if(ch=='Q')
    		{
    			scanf("%d%d",&t,&x);
    			if(t==1) printf("%lld
    ",find(rt[now],1,n,dfn[x],en[x]));
    			else
    			if(t==2) printf("%lld
    ",up1(rt[now],x));
    			else
    			{
    				long long sum=0;
    				for(int j=1;j<=x;j++) scanf("%d",&st[j]),sum+=up1(rt[now],st[j]);
    				sort(st+1,st+1+x,cmp);
    				for(int j=1;j<x;j++) sum-=up1(rt[now],lca(st[j],st[j+1]));
    				printf("%lld
    ",sum);
    			}
    		}
    		else
    		{
    			scanf("%d",&t);
    			now=max(0,now-t);
    		}
    	}
    }
    
  • 相关阅读:
    js函数柯里化
    【转】C# HttpWebRequest提交数据方式
    【转】使用C#发送Http 请求实现模拟登陆(以博客园为例)
    【HTTP】Fiddler(三)- Fiddler命令行和HTTP断点调试
    【HTTP】Fiddler(二)
    【HTTP】Fiddler(一)
    C#版清晰易懂TCP通信原理解析(附demo)
    Html Agility Pack基础类介绍及运用
    使用HtmlAgilityPack批量抓取网页数据
    一款很不错的html转xml工具-Html Agility Pack 实现html转Xml
  • 原文地址:https://www.cnblogs.com/chen1352/p/9610703.html
Copyright © 2020-2023  润新知