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
    
    */
    

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

  • 相关阅读:
    WebMatrix简介与预览
    使用NuGet增加常见包引用
    用Jquery实现的一个Table的帮助js
    使用AspNetPager进行存储过程分页
    Android之旅AppWidget
    SQL积累
    【问题记录】Asp.net WebApplication和WebSite中用户控件的使用区别
    ActionScript 3.0工厂模式实例
    ActionScript 3.0 实现单态模式
    装饰器模式小结
  • 原文地址:https://www.cnblogs.com/ShuraK/p/11256846.html
Copyright © 2011-2022 走看看