zoukankan      html  css  js  c++  java
  • 题解 [ZJOI2019]语言

    题目传送门

    题目大意

    给出一个 (n) 个点的树,现在有 (m) 次操作,每次可以选择一个链 (s,t),,然后这条链上每个点都会增加一个相同属性,问对于每一个点有与它相同属性的有多少个点的答案之和。

    (n,mle10^5)

    思路

    你发现对于每一个点计算的时候答案其实就是所有包含它的链的两端虚树大小。

    于是问题就是如何求虚树大小,你发现如果按 ( ext{dfs}) 序进行排序那么答案就是:

    [sum_{i=1}^{n} ext{dep}(a_i)-sum_{i=1}^{n-1} ext{dep}( ext{lca}(a_i,a_{i+1}))- ext{dep}( ext{lca}(a_1,a_2,...,a_n)) ]

    然后你发现我们这个问题就可以树上差分然后线段树合并解决了,具体见代码。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 100005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    long long ans;
    vector <int> G[MAXN],del[MAXN];
    int n,m,tot,rt[MAXN],dfn[MAXN],par[MAXN][21],dep[MAXN];
    
    void dfs (int u,int fa){
    	par[u][0] = fa,dfn[u] = ++ tot;
    	for (Int i = 1;i <= 20;++ i) par[u][i] = par[par[u][i - 1]][i - 1];
    	for (Int v : G[u]) if (v ^ fa) dep[v] = dep[u] + 1,dfs (v,u);
    }
    
    int getlca (int u,int v){
    	if (dep[u] < dep[v]) swap (u,v);
    	for (Int dis = dep[u] - dep[v],i = 20;~i;-- i) if (dis >> i & 1) u = par[u][i];
    	if (u == v) return u;
    	else{
    		for (Int i = 20;~i;-- i) if (par[u][i] ^ par[v][i]) u = par[u][i],v = par[v][i];
    		return par[u][0];
    	}
    }
    
    struct Segment{
    #define MAXM MAXN*60
    	int cnt,ls[MAXM],rs[MAXM],t[MAXM],s[MAXM],c[MAXM],f[MAXM];
    	//t维护的是dfn最大的,s是dfn是最小的 
    	int query (int u){return f[u] - dep[getlca (s[u],t[u])];}
    	void Pushup (int u){
    		f[u] = f[ls[u]] + f[rs[u]] - dep[getlca (t[ls[u]],s[rs[u]])];
    		t[u] = t[rs[u]] ? t[rs[u]] : t[ls[u]],
    		s[u] = s[ls[u]] ? s[ls[u]] : s[rs[u]];
    	}
    	void modify (int &u,int l,int r,int p,int x){
    		if (!u) u = ++ cnt;
    		if (l == r){
    			c[u] += x,f[u] = c[u] ? dep[p] : 0,t[u] = s[u] = c[u] ? p : 0;
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		if (dfn[p] <= mid) modify (ls[u],l,mid,p,x);
    		else modify (rs[u],mid + 1,r,p,x);
    		Pushup (u);
    	}
    	void Merge (int &u,int v,int l,int r){//学习巨佬的方法可以省空间 
    		if (!u || !v) return u |= v,void ();
    		if (l == r){
    			c[u] += c[v],f[u] |= f[v],s[u] |= s[v],t[u] |= t[v];
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		Merge (ls[u],ls[v],l,mid),Merge (rs[u],rs[v],mid + 1,r);
    		Pushup (u);
    	}
    }Tree;
    
    void Solve (int u){
    	for (Int v : G[u]) if (v ^ par[u][0]) Solve (v);
    	for (Int v : del[u]) Tree.modify (rt[u],1,n,v,-1);
    	ans += Tree.query (rt[u]),Tree.Merge (rt[par[u][0]],rt[u],1,n);  
    }
    
    signed main(){
    	read (n,m);
    	for (Int i = 2,u,v;i <= n;++ i) read (u,v),G[u].push_back (v),G[v].push_back (u);
    	dfs (1,0);for (Int i = 1,u,v,lca;i <= m;++ i){
    		read (u,v),lca = getlca (u,v);
    		Tree.modify (rt[u],1,n,u,1),Tree.modify (rt[u],1,n,v,1);
    		Tree.modify (rt[v],1,n,u,1),Tree.modify (rt[v],1,n,v,1);
    		del[lca].push_back (u),del[lca].push_back (v);
    		del[par[lca][0]].push_back (u),del[par[lca][0]].push_back (v);   
    	}
    	Solve (1),write (ans >> 1),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    一个程序员的负罪感
    【软件安装记录篇】本地虚拟机Centos7快速安装MySQL
    三分钟熟悉进制转换与位运算
    Base64 编码原理
    Java 注解
    数据结构之链表-动图演示
    数据结构之红黑树-动图演示(下)
    数据结构之红黑树-动图演示(上)
    通过TreeMap 和 冒泡算法对JSON 进行排序
    Quartz 之 windowService
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13715198.html
Copyright © 2011-2022 走看看