zoukankan      html  css  js  c++  java
  • [BZOJ3460] Jc的宿舍

    bzoj
    题面放一下

    Description

    WC2014后无数人来膜拜jc,但是来膜拜的人实在太多了, 而且很多人是一连膜拜好几天。所以jc给这些人建了一座树 形的宿舍,而根节点(1号节点)住着jc。然而,由于设计 的原因,宿舍中只有一个水龙头。于是晚上打水就成了问题。 所有人都有一个大小不同的水桶,第i个结点住着的人的水 桶灌满要Ti的时间。水龙头一开始在jc的宿舍,但是水龙 头的位置会发生变化。当一个人去打水,他走的一定是到水 龙头的最短距离,而且他路过的所有宿舍中住的人都会和他 一起去打水。现在有n个人入住,发生了m个事件。
    1.C i 表示水龙头在第i个宿舍
    2.Q i 表示住在i宿舍的人出发去打水。
    对于每个Q i,你需要告诉jc这次去打水的所有人最少的 总等待时间。

    Input

    第一行三个整数n,m,key,接下来一行n个整数表示Ti(小于等于10^7),接下来一行n个数表示每个节点的父亲,保证根节点的父亲为0。接下来m行每行表述一个事件。对于每个Q操作,若输入为Q k,则实际的(k=(k+(pre \% 2)*key) \% n+1)(pre)为上一个询问的答案,若是第一个 询问则(pre=0)。一开始水龙头在1号节点。

    sol

    每一次的询问就是查询树上从(k)点到水龙头位置的路径信息。
    想写树上莫队。发现强制在线?
    仔细想一下发现这个强制在线是假的,因为一来修改操作没有加密,二来(pre)只会导致询问有两种不同可能。只要对这两种分别求解在输出的时候判一下就好了。

    莫队维护的东西是所有人的总等待时间。按照贪心的思路,显然是打水时长小的人排在前面。
    我们现在考虑新加入一个打水时长为(time)的人。那么这个人就要想办法插到打水队伍里面。因为打水时间相同的人顺序任意,我们假设他插到了与他打水时间相同的所有人中的最后一个位置。
    那么这时候,排在他前面的人的等待时间不会变。他自己的等待时间为(time+)所有排在他前面,打水时间小于等于(time)的时长之和。而排在他后面的人,每个人的打水时长都增加了(time)
    所以就能轻松地写出每次加入/删除一个点后答案的变化量了。
    把打水时间离散化后相当于前缀和、后缀和的形式,直接树状数组一波。

    code

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define ll long long
    int gi()
    {
        int x=0,w=1;char ch=getchar();
        while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
        if (ch=='-') w=0,ch=getchar();
        while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return w?x:-x;
    }
    const int N = 1e5+5;
    int n,block,m,key,val[N],o[N],len,to[N<<1],nxt[N<<1],head[N],cnt;
    int fa[N],dep[N],sz[N],son[N],top[N],dfn[N];
    int ccnt,bl[N],s[N],tp,lst=1,vis[N];
    ll c1[N],c2[N],Ans,ans[N],pre;
    struct query{
    	int u,v,id;
    	bool operator < (const query &b) const
    		{
    			if (bl[u]!=bl[b.u]) return bl[u]<bl[b.u];
    			return bl[v]<bl[b.v];
    		}
    }q[N];
    void link(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;}
    void dfs1(int u,int f)
    {
    	fa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
    	for (int e=head[u];e;e=nxt[e])
    	{
    		int v=to[e];if (v==f) continue;
    		dfs1(v,u);
    		sz[u]+=sz[v];if (sz[v]>sz[son[u]]) son[u]=v;
    	}
    }
    void dfs2(int u,int up)
    {
    	top[u]=up;dfn[++cnt]=u;int ttp=tp;
    	if (son[u]) dfs2(son[u],up);
    	if (tp-ttp>=block) {++ccnt;while (tp>ttp) bl[s[tp--]]=ccnt;}
    	for (int e=head[u];e;e=nxt[e])
    	{
    		int v=to[e];if (v==fa[u]||v==son[u]) continue;
    		dfs2(v,v);
    		if (tp-ttp>=block) {++ccnt;while (tp>ttp) bl[s[tp--]]=ccnt;}
    	}
    	s[++tp]=u;
    }
    int getlca(int u,int v)
    {
    	while (top[u]^top[v])
    	{
    		if (dep[top[u]]<dep[top[v]]) swap(u,v);
    		u=fa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v;
    }
    void Add(int pos,int val)
    {
    	for (int k=pos;k<=len;k+=k&-k)
    		c1[k]+=val*o[pos],c2[k]+=val;
    }
    ll Sum(int k){ll res=0;while(k)res+=c1[k],k^=k&-k;return res;}
    ll Size(int k){ll res=0;while(k)res+=c2[k],k^=k&-k;return res;}
    void update(int x)
    {
    	if (!vis[x])
    	{
    		Ans+=o[val[x]]+Sum(val[x])+(ll)o[val[x]]*(Size(len)-Size(val[x]));
    		Add(val[x],1);vis[x]=1;
    	}
    	else
    	{
    		Add(val[x],-1);vis[x]=0;
    		Ans-=o[val[x]]+Sum(val[x])+(ll)o[val[x]]*(Size(len)-Size(val[x]));
    	}
    }
    void change(int u,int v)
    {
    	while (u^v)
    		if (dep[u]>dep[v])  update(u),u=fa[u];
    		else update(v),v=fa[v];
    }
    int main()
    {
    	n=gi();block=pow(n,0.6);m=gi();key=gi();
    	for (int i=1;i<=n;++i) val[i]=o[i]=gi();
    	sort(o+1,o+n+1);len=unique(o+1,o+n+1)-o-1;
    	for (int i=1;i<=n;++i) val[i]=lower_bound(o+1,o+len+1,val[i])-o;
    	for (int i=1;i<=n;++i)
    	{
    		int f=gi();
    		if (f) link(f,i),link(i,f);
    	}
    	dfs1(1,0);cnt=0;dfs2(1,1);cnt=0;
    	if (tp) {++ccnt;while (tp) bl[s[tp--]]=ccnt;}
    	for (int i=1;i<=m;++i)
    	{
    		char ch=getchar();
    		while (ch!='C'&&ch!='Q') ch=getchar();
    		if (ch=='C') lst=gi();
    		else{
    			int k=gi();
    			q[++cnt]=(query){lst,k%n+1,cnt};
    			if (dfn[q[i].u]>dfn[q[i].v]) swap(q[i].u,q[i].v);
    			q[++cnt]=(query){lst,(k+key)%n+1,cnt};
    			if (dfn[q[i].u]>dfn[q[i].v]) swap(q[i].u,q[i].v);
    		}
    	}
    	sort(q+1,q+cnt+1);
    	change(q[1].u,q[1].v);
    	int gg=getlca(q[1].u,q[1].v);
    	update(gg);ans[q[1].id]=Ans;update(gg);
    	for (int i=2;i<=cnt;++i)
    	{
    		change(q[i].u,q[i-1].u);
    		change(q[i].v,q[i-1].v);
    		gg=getlca(q[i].u,q[i].v);
    		update(gg);ans[q[i].id]=Ans;update(gg);
    	}
    	for (int i=1;(i<<1)<=cnt;++i)
    		if (pre&1) printf("%lld
    ",pre=ans[i<<1]);
    		else printf("%lld
    ",pre=ans[(i<<1)-1]);
    	return 0;
    }
    
  • 相关阅读:
    【Python3】调用webserver接口
    【Robot Framework】字符串判断,if语句多执行条件,多执行语句
    【Robot Framework】BuiltIn库
    jenkins运行报错的两个坑
    【Python3】jsonpath-rw处理Json对象
    使用Grunt自动化任务
    用nodesjs+grunt+bower+angularjs搭建项目
    浅谈AngularJS中的$parse和$eval
    AngularJS Controller之间的通信
    AngularJS动态绑定html
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8474686.html
Copyright © 2011-2022 走看看