zoukankan      html  css  js  c++  java
  • bzoj3052: [wc2013]糖果公园

    传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3052

    思路:带修改的树上莫队。

    比不带修改的多加上一个时间维。

    对于时间的移动,那么就模拟一下这段时间的修改,更新答案。

    然后块的大小要设为n^(2/3)。

    至于时间复杂度的证明...

    取B = n ^ (2 / 3),设 nBlo为块的个数,用bloNum[v]来代表v所在块的编号。(block number)
    则同一个块内任意两结点的距离为O(n ^ (2 / 3))的。
    按照之前我说的方式对询问进行排序,按顺序作答。
    注意到(bloNum[curV], bloNum[curU])一共有nBlo ^ 2个取值。
    那么如果移动一次,curV还在原来的块,curU还在原来的块,这种移动的总时间复杂度是O(nBlo ^ 2 * q)的。(因为curTi还要移动)
    如果移动一次,curV不在原来的块,curU不在原来的块,这种移动发生的次数最多为 nBlo ^ 2。因为我是排好序的了嘛,相同块的是放在一起的。而这种移动发生一次最坏是O(n + n + q) = O(n)。(n、q是同阶的)
    所以这样回答所有询问,时间复杂度就是O(nBlo ^ 2 * n)的。
    由于B = n ^ (2 / 3),块的大小介于[B, 3 * B]之间。
    则nBlo = O(n ^ (1 / 3))
    则时间复杂度为O(n ^ (5 / 3))。
    ——来自vfk的博客http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

    然后就没有然后了。

    (一不小心TLE了3次.....捂脸,好像块的大小设为小于n^(2/3)要快一些...)


    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=100010,maxm=200010,maxk=20;
    using namespace std;
    typedef long long ll;
    struct oper{int x,v;}op[maxn];
    struct que{int id,u,v,t;}q[maxn];
    int n,m,Q,w[maxn],v[maxn],fa[maxn][maxk],dep[maxn],s[maxn],c[maxn],tim,ask,sz,cnt,bel[maxn];
    int pre[maxm],now[maxn],son[maxm],tot,timm,dfn[maxn],sta[maxn],top;
    ll ans[maxn],res;bool bo[maxn];char ch;
    
    void read(int &x){
    	for (ch=getchar();!isdigit(ch);ch=getchar());
    	for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    }
    void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
    bool cmp(que a,que b){
    	if (bel[a.u]!=bel[b.u]) return bel[a.u]<bel[b.u];
        else if (bel[a.v]!=bel[b.v]) return bel[a.v]<bel[b.v];
        else return a.t<b.t;
    }
    
    void getfa(int x,int f){
    	dfn[x]=++timm,dep[x]=dep[f]+1,fa[x][0]=f;
    	for (int i=1;i<maxk;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    	for (int y=now[x];y;y=pre[y]) if (son[y]!=f) getfa(son[y],x);
    }
    
    int lca(int u,int v){
    	if (dep[u]<dep[v]) swap(u,v);
    	for (int i=0,h=dep[u]-dep[v];h;i++,h>>=1) if (h&1) u=fa[u][i];
    	if (u==v) return u;
    	for (int i=maxk-1;i>=0;i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    	return fa[u][0];
    }
    
    void getbck(int x,int f){
    	int bot=top;
    	for (int y=now[x];y;y=pre[y])
    		if (son[y]!=f){
    			getbck(son[y],x);
    			if (top-bot>=sz) for (++cnt;top!=bot;) bel[sta[top--]]=cnt;
    		}
    	sta[++top]=x;
    }
    
    void update(int x){
    	if (bo[x]) res-=1ll*v[c[x]]*w[s[c[x]]--];
    	else res+=1ll*v[c[x]]*w[++s[c[x]]];
    	bo[x]^=1;
    }
    
    void update(int u,int v){
    	if (dep[u]<dep[v]) swap(u,v);
    	while (dep[u]!=dep[v]) update(u),u=fa[u][0];
    	while (u!=v) update(u),update(v),u=fa[u][0],v=fa[v][0];
    }
    
    void change(int t){
    	int x=op[t].x;
    	if (bo[x]){
    		res-=1ll*v[c[x]]*w[s[c[x]]--];
    		res+=1ll*v[op[t].v]*w[++s[op[t].v]];
    	}
    	swap(op[t].v,c[x]);
    }
    
    void updatet(int t1,int t2){
    	for (int i=t1+1;i<=t2;i++) change(i);
    	for (int i=t1;i>=t2+1;i--) change(i);
    }
    
    void work(int k){
    	update(q[k-1].u,q[k].u),update(q[k-1].v,q[k].v),updatet(q[k-1].t,q[k].t);
    	int x=lca(q[k].u,q[k].v);update(x),ans[q[k].id]=res,update(x);
    }
    
    int main(){
    	//freopen("aa.in","r",stdin),freopen("aa.out","w",stdout);
    	scanf("%d%d%d",&n,&m,&Q);sz=(int)pow(n,2.0/3.0)*0.7;
    	for (int i=1;i<=m;i++) scanf("%d",&v[i]);
    	for (int i=1;i<=n;i++) scanf("%d",&w[i]);
    	for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
    	for (int i=1;i<=n;i++) scanf("%d",&c[i]);
    	for (int i=1,x,y,z;i<=Q;i++){
    		scanf("%d%d%d",&x,&y,&z);
    		if (!x) op[++tim]=(oper){y,z};
    		else q[++ask]=(que){ask,y,z,tim};
    	}
    	getfa(1,0),getbck(1,0);
    	while (top) bel[sta[top--]]=cnt;
    	for (int i=1;i<=ask;i++) if (bel[q[i].u]>bel[q[i].v]) swap(q[i].u,q[i].v);
    	sort(q+1,q+1+ask,cmp);
    	//for (int i=1;i<=ask;i++) printf("%d
    ",bel[q[i].u]);
    	q[0]=(que){0,1,1,0};
    	for (int i=1;i<=ask;i++) work(i);
    	for (int i=1;i<=ask;i++) printf("%lld
    ",ans[i]);
    	return 0;
    }
    
    /*
    4 3 5
    1 9 2
    7 6 5 1
    2 3
    3 1
    3 4
    1 2 3 2
    1 1 2
    1 4 2
    0 2 1
    1 1 2
    1 4 2
    */
    
    /*
    5 5 5
    6 3 7 4 10 
    1 4 2 3 4 
    1 2
    2 3
    1 4
    2 5
    3 3 3 4 5 
    1 4 2
    1 5 3
    0 3 1
    0 2 3
    1 3 2
    */


  • 相关阅读:
    并查集图冲突hdu1272
    CentOS 7通过yum安装fcitx五笔输入法
    近期的技术问题让云供应商进行预设加密
    POJ 1166 The Clocks (暴搜)
    windows中的mysql修改管理员密码
    Visio画UML类图、序列图 for Java
    js中的时间与毫秒数互相转换
    java.lang.OutOfMemoryError: unable to create new native thread 居然是MQ问题
    WEB移动应用框架构想(转载)
    Android SDK安装教程
  • 原文地址:https://www.cnblogs.com/thythy/p/5493542.html
Copyright © 2011-2022 走看看