zoukankan      html  css  js  c++  java
  • 洛谷P4606 [SDOI2018]战略游戏 【圆方树 + 虚树】

    题目链接

    洛谷P4606
    双倍经验:弱化版

    题解

    两点之间必经的点就是圆方树上两点之间的圆点
    所以只需建出圆方树
    每次询问建出虚树,统计一下虚树边上有多少圆点即可
    还要讨论一下经不经过根(1)的情况

    P4606

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 200005,maxm = 100005,INF = 1000000000;
    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 << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int h[maxn],ne = 1,hh[maxn],Ne = 1;
    struct EDGE{int to,nxt;}ed[maxn << 2],e[maxn << 2];
    inline void build(int u,int v){
    	e[++Ne] = (EDGE){v,hh[u]}; hh[u] = Ne;
    	e[++Ne] = (EDGE){u,hh[v]}; hh[v] = Ne;
    }
    inline void add(int u,int v){
    	ed[++ne] = (EDGE){v,h[u]}; h[u] = ne;
    	ed[++ne] = (EDGE){u,h[v]}; h[v] = ne;
    }
    int n,m,N,dfn[maxn],low[maxn],st[maxn],top,cnt;
    void dfs(int u,int last){
    	dfn[u] = low[u] = ++cnt;
    	st[++top] = u;
    	for (int k = hh[u],to; k; k = e[k].nxt){
    		if (k == last) continue;
    		if (!dfn[to = e[k].to]){
    			dfs(to,k ^ 1);
    			low[u] = min(low[u],low[to]);
    			if (low[to] >= dfn[u]){
    				++N;
    				do{add(st[top],N);}while (st[top--] != to);
    				add(N,u);
    			}
    		}
    		else low[u] = min(low[u],dfn[to]);
    	}
    }
    int K,a[maxn],fa[maxn][20],d[maxn][20],Dfn[maxn],dep[maxn],dfc;
    void DFS(int u){
    	Dfn[u] = ++dfc; d[u][0] = (u <= n);
    	REP(i,19){
    		fa[u][i] = fa[fa[u][i - 1]][i - 1];
    		d[u][i] = d[u][i - 1] + d[fa[u][i - 1]][i - 1];
    	}
    	Redge(u) if ((to = ed[k].to) != fa[u][0]){
    		fa[to][0] = u; dep[to] = dep[u] + 1; DFS(to);
    	}
    }
    inline int lca(int u,int v){
    	if (dep[u] < dep[v]) swap(u,v);
    	for (int i = 0,D = dep[u] - dep[v]; (1 << i) <= D; i++)
    		if (D & (1 << i)) u = fa[u][i];
    	if (u == v) return u;
    	for (int i = 19; ~i; i--)
    		if (fa[u][i] != fa[v][i]){
    			u = fa[u][i];
    			v = fa[v][i];
    		}
    	return fa[u][0];
    }
    inline int getup(int u,int v){
    	if (u == v) return 0;
    	int re = -(u <= n);
    	for (int i = 19; ~i; i--)
    		if (fa[u][i] && dep[fa[u][i]] >= dep[v]){
    			re += d[u][i];
    			u = fa[u][i];
    		}
    	return re;
    }
    inline bool cmp(const int& a,const int& b){
    	return Dfn[a] < Dfn[b];
    }
    int pre[maxn];
    void work(){
    	st[top = 1] = 1; int tot = 0,M = K;
    	sort(a + 1,a + 1 + K,cmp);
    	for (int i = 1; i <= K; i++){
    		int u = a[i],p = lca(u,st[top]);
    		if (u == 1) tot = INF;
    		if (p == st[top]) {if (u != st[top]) st[++top] = u;}
    		else {
    			while (true){
    				if (dep[p] >= dep[st[top - 1]]){
    					pre[st[top--]] = p; if (p == 1) tot++;
    					if (st[top] != p) st[++top] = p,a[++M] = p;
    					break;
    				}
    				pre[st[top]] = st[top - 1];
    				if (st[top - 1] == 1) tot++;
    				top--;
    			}
    			if (u != st[top]) st[++top] = u;
    		}
    	}
    	while (top > 1){
    		pre[st[top]] = st[top - 1];
    		if (st[top - 1] == 1) tot++;
    		top--;
    	}
    	if (tot < INF) a[++M] = 1;
    	int ans = 0;
    	for (int i = 1; i <= M; i++){
    		int u = a[i];
    		if (u == 1){
    			if (i > K && tot > 1) ans++;
    			continue;
    		}
    		if (pre[u] != 1 || (pre[u] == 1 && tot > 1)) ans += getup(u,pre[u]);
    		if (i > K) ans += (u <= n);
    		pre[u] = 0;
    	}
    	printf("%d
    ",ans);
    }
    int main(){
    	int T = read();
    	while (T--){
    		cls(dfn); cls(h); cls(hh);
    		ne = Ne = 1; cnt = dfc = top = 0;
    		N = n = read(); m = read();
    		REP(i,m) build(read(),read());
    		dfs(1,0); DFS(1);
    		int q = read();
    		while (q--){
    			K = read();
    			REP(i,K) a[i] = read();
    			work();
    		}
    	}
    	return 0;
    }
    
    

    P4320

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 1000005,maxm = 100005,INF = 1000000000;
    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 << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int h[maxn],ne = 1,hh[maxn],Ne = 1;
    struct EDGE{int to,nxt;}ed[maxn << 2],e[maxn << 2];
    inline void build(int u,int v){
    	e[++Ne] = (EDGE){v,hh[u]}; hh[u] = Ne;
    	e[++Ne] = (EDGE){u,hh[v]}; hh[v] = Ne;
    }
    inline void add(int u,int v){
    	ed[++ne] = (EDGE){v,h[u]}; h[u] = ne;
    	ed[++ne] = (EDGE){u,h[v]}; h[v] = ne;
    }
    int n,m,N,val[maxn];
    int dfn[maxn],low[maxn],st[maxn],top,cnt;
    void dfs(int u,int last){
    	dfn[u] = low[u] = ++cnt;
    	st[++top] = u;
    	for (int k = hh[u],to; k; k = e[k].nxt){
    		if (k == last) continue;
    		if (!dfn[to = e[k].to]){
    			dfs(to,k ^ 1);
    			low[u] = min(low[u],low[to]);
    			if (low[to] >= dfn[u]){
    				++N;
    				do{add(st[top],N);}while (st[top--] != to);
    				add(N,u);
    			}
    		}
    		else low[u] = min(low[u],dfn[to]);
    	}
    }
    int fa[maxn][20],d[maxn][20],Dfn[maxn],dep[maxn],dfc;
    void DFS(int u){
    	Dfn[u] = ++dfc; d[u][0] = (u <= n);
    	REP(i,19){
    		fa[u][i] = fa[fa[u][i - 1]][i - 1];
    		d[u][i] = d[u][i - 1] + d[fa[u][i - 1]][i - 1];
    	}
    	Redge(u) if ((to = ed[k].to) != fa[u][0]){
    		fa[to][0] = u; dep[to] = dep[u] + 1; DFS(to);
    	}
    }
    int dis(int u,int v){
    	int re = 0;
    	if (dep[u] < dep[v]) swap(u,v);
    	for (int i = 0,D = dep[u] - dep[v]; (1 << i) <= D; i++)
    		if (D & (1 << i)){
    			re += d[u][i];
    			u = fa[u][i];
    		}
    	if (u == v) return re + 1;
    	for (int i = 19; ~i; i--)
    		if (fa[u][i] != fa[v][i]){
    			re += d[u][i] + d[v][i];
    			u = fa[u][i];
    			v = fa[v][i];
    		}
    	re += d[u][0] + d[v][0];
    	if (fa[u][0] <= n) re++;
    	return re;
    }
    int main(){
    	N = n = read(); m = read();
    	REP(i,m) build(read(),read());
    	dfs(1,0);
    	DFS(1);
    	int q = read(),u,v;
    	while (q--){
    		u = read(); v = read();
    		printf("%d
    ",dis(u,v));
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    DGA域名可以是色情网站域名
    使用cloudflare加速你的网站隐藏你的网站IP
    167. Two Sum II
    leetcode 563. Binary Tree Tilt
    python 多线程
    leetcode 404. Sum of Left Leaves
    leetcode 100. Same Tree
    leetcode 383. Ransom Note
    leetcode 122. Best Time to Buy and Sell Stock II
    天津Uber优步司机奖励政策(12月28日到12月29日)
  • 原文地址:https://www.cnblogs.com/Mychael/p/9194811.html
Copyright © 2011-2022 走看看