zoukankan      html  css  js  c++  java
  • [Nowcoder113E]弹球弹弹弹_线段树

    弹球弹弹弹

    题目大意:有n个位置,标号为1到n的整数,m次操作,第i次操作放置一个弹球在b[i] xor c[i-1]处,并询问b[i] xor c[i-1]处弹球个数c[i]每次操作后,在x处的弹球被弹到a[x],规定c[0]=0。

    数据范围:1<=n,m<=500000。


    题解

    这个题真的是,说起来容易写起来是真的恶心.....

    首先要读题,每次操作是这样的:

    先加进来一个球,然后查询当前位置的个数,接着直接把每个位置弹到对应位置。

    显然,每个点有一条出边,这是一个基环内向森林的模型。

    我们把询问分成两种情况讨论:第一种是查询不在环上的点,第二种是环上的点。

    第一种怎么弄呢?

    首先发现,如果一个球进了环就出不来了,所以我们只需要统计这个点子树内的情况(我们以基环树的环为根,每个数的根就是对应环上的点)。

    发现,如果一个点子树内的点$u$满足加入树的时间$time_u$加上和当前点的距离$dep[u]-dep[now]$等于当前时间$nowtime$的话,这个点就可以被统计到。

    故此把每个点的权值设为$time_x+dep_x$,只需要查询当前点的子树中,权值等于$nowtime+dep[x]$的点个数。

    这个可以用线段树平衡树啊什么的实现,我这里用的是线段树

    具体地,我们对于每个权值开一棵线段树,最多需要开$maxtime + maxdep$棵。

    线段树上每个节点维护其管辖区间里,所有权值等于当前线段树权值的点个数。

    修改就直接在对应权值里修改就好了。

    好,第一种情况我们就处理完了,复杂度是$O(nlogn)$。

    看第二种情况。

    第二种情况的答案贡献有两个渠道,第一个是本身修改就在环上修改的点,第二个是从树上走到环里的点。

    第一个好弄,我们对每个环建立一个循环数组,环上每个点有个偏移量$skew_x$表示其距离环上拟定$0$号点的距离。

    每次修改我们都直接修改到对应的节点上,就是修改到一次都没弹过的节点上,查询也上那儿查。

    第一个就弄完了。

    看看第二个:

    第二个的话,就是修改是在树上修改,但是走到环上了。

    怎么办呢?我们就弄一个$vector$叫$Fix_time$。

    $Fix_i$表示所有在第$i$时刻的点集合。

    对于一个在树上修改的点,我们把它扔进$Fix_{dep[x]+nowtime}$。

    当处理完修改和查询之后,我们处理当前时刻的$Fix$数组。

    每次只需要看一下,对应的点需要加到没有弹过的哪个环上节点就好了。

    难写难调。

    还有,这个题好像平衡树卡常,线段树秒过。

    我写的线段树

    代码

    这个是删掉所有调试注释的,方便取用。

    #include <bits/stdc++.h>
    
    #define N 500010 
    
    using namespace std;
    
    struct Edge {
    	int to[N << 1], nxt[N << 1], tot, head[N];
    	inline void add(int x, int y) {
    		to[ ++ tot] = y;
    		nxt[tot] = head[x];
    		head[x] = tot;
    	}
    }G1,G2;
    
    int d[N], dep[N], qu[N], dfn[N], Q[N], vis[N], sk[N], sz[N], top[N];
    
    int root[N << 1];
    
    bool disp[N];
    
    queue<int> q;
    
    vector<int> Round[N], Ans[N];
    
    int cnt;
    
    vector<int> Fix[N << 1];
    
    struct Segment_Tree {
    	int ls, rs, sum;
    }a[N << 8];
    
    char *p1, *p2, buf[100000];
    
    #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )
    
    int rd() {
    	int x = 0, f = 1;
    	char c = nc();
    	while (c < 48) {
    		if (c == '-')
    			f = -1;
    		c = nc();
    	}
    	while (c > 47) {
    		x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
    	}
    	return x * f;
    }
    
    int n;
    
    void toposort() {
    	for (int i = 1; i <= n; i ++ ) {
    		if (!d[i]) {
    			vis[i] = -1;
    			q.push(i);
    		}
    	}
    	while (!q.empty()) {
    		int x = q.front();
    		q.pop();
    		for (int i = G1.head[x]; i; i = G1.nxt[i]) {
    			d[G1.to[i]] -- ;
    			if (!d[G1.to[i]]) {
    				q.push(G1.to[i]);
    				vis[G1.to[i]] = -1;
    			}
    		}
    	}
    }
    
    inline void pushup(int x) {
    	int ls = a[x].ls, rs = a[x].rs;
    	a[x].sum = 0;
    	if (ls) {
    		a[x].sum += a[ls].sum;
    	}
    	if (rs) {
    		a[x].sum += a[rs].sum;
    	}
    }
    
    void update(int x, int val, int l, int r, int &p) {
    	if (!p) {
    		p = ++cnt;
    	}
    	if (l == r) {
    		a[p].sum ++ ;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if (x <= mid) {
    		update(x, val, l, mid, a[p].ls);
    	}
    	else {
    		update(x, val, mid + 1, r, a[p].rs);
    	}
    	pushup(p);
    }
    
    int query(int x, int y, int l, int r, int p) {
    	if (!p) {
    		return 0;
    	}
    	if (x <= l && r <= y) {
    		return a[p].sum;
    	}
    	int mid = (l + r) >> 1, ans = 0;
    	if (x <= mid) {
    		ans += query(x, y, l, mid, a[p].ls);
    	}
    	if (mid < y) {
    		ans += query(x, y, mid + 1, r, a[p].rs);
    	}
    	return ans;
    }
    
    void dfs_init(int p, int fa, int anc) {
    	dfn[p] = ++dfn[0];
    	top[p] = anc;
    	sz[p] = 1;
    	dep[p] = dep[fa] + 1;
    	for (int i = G2.head[p]; i; i = G2.nxt[i]) {
    		if (G2.to[i] != fa && vis[G2.to[i]] == -1) {
    			dfs_init(G2.to[i], p, anc);
    			sz[p] += sz[G2.to[i]];
    		}
    	}
    }
    
    int main() {
    	n = rd();
    	for (int i = 1; i <= n; i ++ ) {
    		qu[i] = rd();
    		G1.add(i, qu[i]);
    		d[qu[i]] ++ ;
    	}
    
    	toposort();
    	for (int i = 1; i <= n; i ++ ) {
    		if (vis[i]) {
    			G2.add(qu[i], i);
    		}
    	}
    
    	for (int i = 1; i <= n; i ++ ) {
    		if (!vis[i] && !disp[i]) {
    			vis[0] ++ ;
    			int t = i;
    			int now = 0;
    			do {
    				vis[t] = vis[0];
    				disp[t] = true;
    				Round[vis[0]].push_back(t);
    				Ans[vis[0]].push_back(0);
    				now ++ ;
    				sk[t] = now - 1;
    
    				dfs_init(t, t, t);
    
    				t = qu[t];
    			} while(t != i);
    		}
    	}
    
    	int m = rd();
    	int lastans = 0;
    	for (int i = 1; i <= m; i ++ ) {
    		int x = rd();
    		if (vis[x] == -1) {
    			update(dfn[x], 1, 1, n, root[i + dep[x]]);
    			lastans = query(dfn[x], dfn[x] + sz[x] - 1, 1, n, root[i + dep[x]]);
    			printf("%d
    ", lastans);
    			Fix[i + dep[x] - 2].push_back(x);
    		}
    		else {
    			int Round_length = Round[vis[x]].size();
    			int now_position = ((sk[x] - i + 1) % Round_length + Round_length) % Round_length;
    			Ans[vis[x]][now_position] ++ ;
    			lastans = Ans[vis[x]][now_position];
    			printf("%d
    ", lastans);
    		}
    		int len = Fix[i].size();
    		for (int j = 0; j < len; j ++ ) {
    			int y = top[Fix[i][j]];
    			int Round_length = Round[vis[y]].size();
    			int now_position = ((sk[y] - i) % Round_length + Round_length) %Round_length;
    			Ans[vis[y]][now_position] ++ ;
    		}
    	}
    	return 0;
    }
    

    这个嘛....是调的时候加的调试信息....博主只会用输出调试所以调完的代码都比较壮观,这个题恶心我两个小时特殊记录一下.....(有兴趣可以看看爽一爽顺便$diss$博主傻逼/xk)

    #include <bits/stdc++.h>
    
    #define N 500010 
    
    using namespace std;
    
    struct Edge {
    	int to[N << 1], nxt[N << 1], tot, head[N];
    	inline void add(int x, int y) {
    		to[ ++ tot] = y;
    		nxt[tot] = head[x];
    		head[x] = tot;
    	}
    }G1,G2;
    
    int d[N], dep[N], qu[N], dfn[N], Q[N], vis[N], sk[N], sz[N], top[N];
    
    int root[N << 1];
    
    bool disp[N];
    
    queue<int> q;
    
    vector<int> Round[N], Ans[N];
    
    int cnt;
    
    vector<int> Fix[N << 1];
    
    struct Segment_Tree {
    	int ls, rs, sum;
    }a[N << 8];
    
    char *p1, *p2, buf[100000];
    
    #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )
    
    int rd() {
    	int x = 0, f = 1;
    	char c = nc();
    	while (c < 48) {
    		if (c == '-')
    			f = -1;
    		c = nc();
    	}
    	while (c > 47) {
    		x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
    	}
    	return x * f;
    }
    
    int n;
    
    void toposort() {
    	for (int i = 1; i <= n; i ++ ) {
    		if (!d[i]) {
    			vis[i] = -1;
    			q.push(i);
    		}
    	}
    	while (!q.empty()) {
    		int x = q.front();
    		q.pop();
    		for (int i = G1.head[x]; i; i = G1.nxt[i]) {
    			d[G1.to[i]] -- ;
    			if (!d[G1.to[i]]) {
    				q.push(G1.to[i]);
    				vis[G1.to[i]] = -1;
    			}
    		}
    	}
    }
    
    inline void pushup(int x) {
    	int ls = a[x].ls, rs = a[x].rs;
    	a[x].sum = 0;
    	if (ls) {
    		a[x].sum += a[ls].sum;
    	}
    	if (rs) {
    		a[x].sum += a[rs].sum;
    	}
    }
    
    void update(int x, int val, int l, int r, int &p) {
    	// printf("A %d %d %d %d %d %d
    ", x, val, l, r, p, a[p].sum);
    	if (!p) {
    		p = ++cnt;
    	}
    	// printf("B %d %d %d %d %d %d
    ", x, val, l, r, p, a[p].sum);
    	if (l == r) {
    		a[p].sum ++ ;
    		return;
    	}
    	// printf("C %d %d %d %d %d %d
    ", x, val, l, r, p, a[p].sum);
    	int mid = (l + r) >> 1;
    	if (x <= mid) {
    		update(x, val, l, mid, a[p].ls);
    	}
    	else {
    		update(x, val, mid + 1, r, a[p].rs);
    	}
    	pushup(p);
    	// printf("D %d %d %d %d %d %d
    ", x, val, l, r, p, a[p].sum);
    }
    
    int query(int x, int y, int l, int r, int p) {
    	if (!p) {
    		return 0;
    	}
    	if (x <= l && r <= y) {
    		return a[p].sum;
    	}
    	int mid = (l + r) >> 1, ans = 0;
    	if (x <= mid) {
    		ans += query(x, y, l, mid, a[p].ls);
    	}
    	if (mid < y) {
    		ans += query(x, y, mid + 1, r, a[p].rs);
    	}
    	return ans;
    }
    
    void dfs_init(int p, int fa, int anc) {
    	dfn[p] = ++dfn[0];
    	top[p] = anc;
    	sz[p] = 1;
    	dep[p] = dep[fa] + 1;
    	for (int i = G2.head[p]; i; i = G2.nxt[i]) {
    		if (G2.to[i] != fa && vis[G2.to[i]] == -1) {
    			dfs_init(G2.to[i], p, anc);
    			sz[p] += sz[G2.to[i]];
    		}
    	}
    }
    
    int main() {
    	n = rd();
    	for (int i = 1; i <= n; i ++ ) {
    		qu[i] = rd();
    		G1.add(i, qu[i]);
    		d[qu[i]] ++ ;
    	}
    
    	toposort();
    	for (int i = 1; i <= n; i ++ ) {
    		if (vis[i]) {
    			G2.add(qu[i], i);
    		}
    	}
    
    	// for (int i = 1; i <= n; i ++ ) {
    	// 	printf("%d ",vis[i]);
    	// }
    	// puts("");
    
    	for (int i = 1; i <= n; i ++ ) {
    		if (!vis[i] && !disp[i]) {
    			// printf("i-> %d
    ", i);
    			vis[0] ++ ;
    			int t = i;
    			int now = 0;
    			do {
    				// printf("t-> %d
    ", t);
    				vis[t] = vis[0];
    				disp[t] = true;
    				Round[vis[0]].push_back(t);
    				Ans[vis[0]].push_back(0);
    				now ++ ;
    				sk[t] = now - 1;
    
    				dfs_init(t, t, t);
    
    				t = qu[t];
    				// printf("t-> %d
    ", t);
    			} while(t != i);
    			// while (t != i) {
    			// 	vis[t] = vis[0];
    			// 	disp[t] = true;
    			// 	Round[vis[0]].push_back(t);
    			// 	Ans[vis[0]].push_back(0);
    			// 	now ++ ;
    			// 	sk[t] = now - 1;
    
    			// 	dfs_init(t, t, t);
    
    			// 	t = qu[t];
    			// }
    		}
    	}
    
    	// puts("Fuck");
    
    	// printf("%d %d %d %d
    ", sk[2], sk[4], sk[7], sk[10]);
    
    	int m = rd();
    	int lastans = 0;
    	for (int i = 1; i <= m; i ++ ) {
    		int x = rd();
    		// x ^= lastans;
    		// printf("i- %d
    ", i);
    		if (vis[x] == -1) {
    			// printf("A
    ");
    			// printf("%d
    ", i + dep[x]);
    			update(dfn[x], 1, 1, n, root[i + dep[x]]);
    			lastans = query(dfn[x], dfn[x] + sz[x] - 1, 1, n, root[i + dep[x]]);
    			printf("%d
    ", lastans);
    			// printf("Fix %d
    ", i + dep[x] - 2);
    			Fix[i + dep[x] - 2].push_back(x);
    		}
    		else {
    			int Round_length = Round[vis[x]].size();
    			int now_position = ((sk[x] - i + 1) % Round_length + Round_length) % Round_length;
    			// printf("%d %d
    ", Round_length, now_position);
    			Ans[vis[x]][now_position] ++ ;
    			lastans = Ans[vis[x]][now_position];
    			printf("%d
    ", lastans);
    		}
    		int len = Fix[i].size();
    		for (int j = 0; j < len; j ++ ) {
    			// Fix[i][j];
    			int y = top[Fix[i][j]];
    			int Round_length = Round[vis[y]].size();
    			int now_position = ((sk[y] - i) % Round_length + Round_length) %Round_length;
    			// printf("np %d
    ", now_position);
    			// printf("%d %d
    ", Round_length, now_position);
    			Ans[vis[y]][now_position] ++ ;
    		}
    	}
    	return 0;
    }
    /*
    6
    1
    2
    1
    3
    3
    6
    20
    1
    2
    3
    4
    5
    6
    1
    2
    3
    4
    5
    6
    1
    2
    3
    4
    5
    6
    6
    6
    */
    /*
    1 1 1 1 1 1 5 2 1 1 1 2 9 3 1 1 1 3 4 5
    
    */
    

    小结:好题好题,这个出成考试题非常妙啊,好想诶,就是有点难写。当然只是对我来讲,别人肯定分分钟切掉。

  • 相关阅读:
    HDU 5528 Count a * b 欧拉函数
    HDU 5534 Partial Tree 完全背包
    HDU 5536 Chip Factory Trie
    HDU 5510 Bazinga KMP
    HDU 4821 String 字符串哈希
    HDU 4814 Golden Radio Base 模拟
    LA 6538 Dinner Coming Soon DP
    HDU 4781 Assignment For Princess 构造
    LA 7056 Colorful Toy Polya定理
    LA 6540 Fibonacci Tree
  • 原文地址:https://www.cnblogs.com/ShuraK/p/11256846.html
Copyright © 2011-2022 走看看