zoukankan      html  css  js  c++  java
  • 【HNOI2016】网络

    题面

    题解

    考虑整体二分。

    定义整体二分函数solve(l, r, ql, qr)表示操作权值在([l, r])中,对([ql, qr])的询问进行二分。

    这样的话check就会很简单,先按照时间将所有(geq mid)的边加进去,对于每个点判断是不是所有路径都经过了这个点就可以判断这个点的答案是不是(geq mid)

    具体如何判断的话可以用树上差分。

    代码

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #define RG register
    #define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define clear(x, y) memset(x, y, sizeof(x))
    
    inline int read()
    {
    	int data = 0, w = 1; char ch = getchar();
    	while(ch != '-' && (!isdigit(ch))) ch = getchar();
    	if(ch == '-') w = -1, ch = getchar();
    	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    const int maxn(100010), maxm(200010);
    struct edge { int next, to; } e[maxn << 1];
    int head[maxn], e_num, n, m;
    inline void add_edge(int from, int to)
    {
    	e[++e_num] = (edge) {head[from], to};
    	head[from] = e_num;
    }
    
    int size[maxn], heavy[maxn], pos[maxn], fa[maxn], belong[maxn], cnt;
    void dfs(int x)
    {
    	size[x] = 1;
    	for(RG int i = head[x]; i; i = e[i].next)
    	{
    		int to = e[i].to; if(to == fa[x]) continue;
    		fa[to] = x; dfs(to); size[x] += size[to];
    		if(size[heavy[x]] < size[to]) heavy[x] = to;
    	}
    }
    
    void dfs(int x, int chain)
    {
    	pos[x] = ++cnt; belong[x] = chain;
    	if(!heavy[x]) return;
    	dfs(heavy[x], chain);
    	for(RG int i = head[x]; i; i = e[i].next)
    	{
    		int to = e[i].to;
    		if(to == fa[x] || to == heavy[x]) continue;
    		dfs(to, to);
    	}
    }
    
    struct qry { int opt, from, to, dis, id, lca, y; } s[maxm], pl[maxm], pr[maxm];
    int U[maxm], ucnt, ans[maxm], c[maxm];
    
    void update(int x, int v) { while(x <= n) c[x] += v, x += x & -x; }
    int query(int x) { int a = 0; while(x) a += c[x], x -= x & -x; return a; }
    void Div(int l, int r, int ql, int qr)
    {
    	if(ql > qr) return;
    	bool flag = 1; int cntl = 0, cntr = 0;
    	for(RG int i = ql; i <= qr; i++)
    		if(s[i].opt == 2) { flag = 0; break; }
    	if(flag) return;
    	if(l == r)
    	{
    		for(RG int i = ql; i <= qr; i++)
    			if(s[i].id) ans[s[i].id] = l;
    		return;
    	}
    	int mid = (l + r) >> 1, sum = 0;
    	for(RG int i = ql; i <= qr; i++)
    		if(s[i].opt == 2)
    		{
    			if(query(pos[s[i].from] + size[s[i].from] - 1) -
    				query(pos[s[i].from] - 1) == sum) pr[++cntr] = s[i];
    			else pl[++cntl] = s[i];
    		}
    		else if(s[i].dis <= mid)
    		{
    			int d = s[i].opt ? -1 : 1; sum += d;
    			update(pos[s[i].from], d); update(pos[s[i].to], d);
    			update(pos[s[i].lca], -d);
    			if(s[i].lca != 1) update(pos[fa[s[i].lca]], -d);
    			pl[++cntl] = s[i];
    		}
    		else pr[++cntr] = s[i];
    	memcpy(s + ql, pl + 1, sizeof(qry) * cntl);
    	memcpy(s + ql + cntl, pr + 1, sizeof(qry) * cntr);
    	for(RG int i = ql; i <= qr; i++)
    		if(s[i].opt != 2 && s[i].dis <= mid && s[i].y)
    		{
    			int d = s[i].opt ? 1 : -1;
    			update(pos[s[i].from], d); update(pos[s[i].to], d);
    			update(pos[s[i].lca], -d);
    			if(s[i].lca != 1) update(pos[fa[s[i].lca]], -d);
    		}
    	Div(l, mid, ql, ql + cntl - 1), Div(mid + 1, r, ql + cntl, qr);
    }
    
    int main()
    {
    	n = read(), m = read();
    	for(RG int i = 1, a, b; i < n; i++)
    		a = read(), b = read(),
    		add_edge(a, b), add_edge(b, a);
    	dfs(1); dfs(1, 1);
    	for(RG int i = 1; i <= m; i++)
    	{
    		s[i].opt = read();
    		if(s[i].opt == 0)
    		{
    			int x = s[i].from = read(), y = s[i].to = read();
    			U[++ucnt] = -(s[i].dis = read()), s[i].y = 1;
    			while(belong[x] != belong[y])
    			{
    				if(pos[belong[x]] < pos[belong[y]]) std::swap(x, y);
    				x = fa[belong[x]];
    			}
    			s[i].lca = (pos[x] < pos[y] ? x : y);
    		}
    		else if(s[i].opt == 1)
    		{
    			int x = read(); s[i] = s[x]; s[i].opt = 1;
    			s[i].y = s[x].y = 0;
    		}
    		else s[i].from = read(), s[i].id = ++ans[0];
    	}
    	U[++ucnt] = 1; std::sort(U + 1, U + ucnt + 1);
    	ucnt = std::unique(U + 1, U + ucnt + 1) - U - 1;
    	for(RG int i = 1; i <= m; i++) if(s[i].opt != 2)
    		s[i].dis = std::lower_bound(U + 1, U + ucnt + 1, -s[i].dis) - U;
    	for(RG int i = 1; i <= ucnt; i++) U[i] = -U[i];
    	Div(1, ucnt, 1, m);
    	for(RG int i = 1; i <= ans[0]; i++) printf("%d
    ", U[ans[i]]);
    	return 0;
    }
    
  • 相关阅读:
    bzoj5157: [Tjoi2014]上升子序列(树状数组LIS)
    2435: [Noi2011]道路修建(树上操作)
    bzoj1019: [SHOI2008]汉诺塔(动态规划)
    bzoj1103: [POI2007]大都市meg(树链剖分)
    bzoj2190: [SDOI2008]仪仗队(欧拉)
    bzoj4519: [Cqoi2016]不同的最小割(分治最小割)
    bzoj2229: [Zjoi2011]最小割(分治最小割+最小割树思想)
    bzoj1816: [Cqoi2010]扑克牌(二分答案判断)
    [HEOI2015]兔子与樱花
    [POI2009]KAM-Pebbles
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10441341.html
Copyright © 2011-2022 走看看