zoukankan      html  css  js  c++  java
  • 2021“MINIEYE杯”中国大学生算法设计超级联赛(4)1002. Kanade Loves Maze Designing(DFS/树状数组)

    Problem Description

    Kanade is designing a mini-game. It's a puzzle game that orders players to get out of a maze. Players should also collect as many kinds of elements as they can to gain a better score.

    For the easy mode, the maze can be described as a tree. There are n crossings and n−1 undirected passages which make the n crossings connected. The n crossings is numbered with integers from 1 to n. Exactly one element is placed on each crossing. The kind of element placed at crossing i is denoted by an integer ci in the range [1,n].

    To evaluate the maze's difficulty, Kanade wants to know how many kinds of elements appear on p(u,v) for every two integers u,v∈[1,n]. p(u,v) indicates the simple path from crossing u to crossing v in the maze.

    Input

    The first line of input contains one integer T (1≤T≤10), indicating the number of test cases.

    For each test case, the first line contains one integer n (2≤n≤2000), indicating the number of crossings in the maze.

    The second line contains n−1 integers p2,p3,…,pn (pi<i), indicating that the i-th crossing is connected with the pi-th crossing by a passage.

    The third line contains n integers c1,c2,…,cn (1≤ci≤n), indicating that the kind of element placed at crossing i is ci.

    It is promised that for all test cases, ∑n≤5000.

    Output

    For each test case, output n lines. Each line contains two integers. Let ai,j be the number of kinds of elements appear on p(i,j). Let

    f(i,x)=∑j=1nai,jxj−1

    Then for the i-th line, output f(i,19560929)mod(109+7) and f(i,19560929)mod(109+9), space separated.

    Sample Input

    1
    6
    1 1 2 2 3
    1 1 4 5 1 4
    

    Sample Output

    495644981 518101442
    495644981 518101442
    397599492 896634980
    612255048 326063507
    495644981 518101442
    397599492 896634980
    
    
    
    Hint
    Let A=(aij), then for the example, A equals to
    1 1 2 2 1 2
    1 1 2 2 1 2
    2 2 1 3 2 1
    2 2 3 1 2 3
    1 1 2 2 1 2
    2 2 1 3 2 1
    

    写了波暴力卡过了...

    注意到最后输出的形式比较特殊,是每一个点到其他各个点的树上路径的答案进行运算得到的。又注意到点的范围实际上不大(2e3),考虑对每个点dfs得到答案然后计算并输出。问题就转换成了怎么求树上每个点到树根的路径上有多少种不同的点权。因为点权的范围是1到n,因此可以用树状数组维护(桶排序的思想)。每搜索到一个点就直接统计,然后遍历这个点关联的边,如果下一个点的权值已经出现过则不modify,如果没有出现过则让这个位置+1,说明这个位置对应的权值出现过则不用管。注意如果dfs前更新过,dfs完一定要回溯。

    #include <bits/stdc++.h>
    #define mod1 1000000007
    #define mod2 1000000009
    #define C 19560929
    #define int long long
    #define N 2005
    using namespace std;
    int n, head[N], ver[2 * N], Next[2 * N], tot;
    int c[N];
    int num[N];
    void add(int x, int y) {
    	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
    }
    int b[N];
    void modify(int x, int y) {
    	for(; x <= n; x += (x & -x)) b[x] += y;
    }
    int query(int x) {
    	int ans = 0;
    	for(; x; x -= (x & -x)) {
    		ans += b[x];
    	}
    	return ans;
    }
    bitset<2005> bst;
    void dfs(int x, int pre) {
    	num[x] = query(n);
    	//num[x] = bst.count();
    	for(int i = head[x]; i; i = Next[i]) {
    		int y = ver[i];
    		if(y == pre) continue;
    		int tmp = query(c[y]) - query(c[y] - 1);
    		//int tmp = bst[c[y]];
    		if(!tmp) {
    			modify(c[y], 1);
    			//bst[c[y]] = 1;
    		}
    		dfs(y, x);
    		if(!tmp) {
    			modify(c[y], -1);
    			//bst[c[y]] = 0;
    		}
    	} 
    }
    int p1[2005], p2[2005];
    signed main() {
    	int t;
    	cin >> t;
    	p1[1] = p2[1] = 1;
    	for(int i = 2; i <= 2000; i++) {
    		p1[i] = p1[i - 1] * C % mod1;
    		p2[i] = p2[i - 1] * C % mod2;
    	}
    	while(t--) {
    		tot = 0;
    		memset(head, 0, sizeof(head));
    		//bst.reset();
    		scanf("%lld", &n);
    		for(int i = 1; i <= n + 10; i++) b[i] = 0;
    		for(int i = 2; i <= n; i++) {
    			int p;
    			scanf("%lld", &p);
    			add(i, p);
    			add(p, i);
    		}
    		for(int i = 1; i <= n; i++) {
    			scanf("%lld", &c[i]);
    		}
    		for(int i = 1; i <= n; i++) {
    			modify(c[i], 1);
    			//bst[c[i]] = 1;
    			dfs(i, 0);
    			int ans1 = 0, ans2 = 0;
    			for(int j = 1; j<= n; j++) {
    				ans1 = (ans1 + num[j] * p1[j] % mod1) % mod1;
    				ans2 = (ans2 + num[j] * p2[j] % mod2) % mod2;
    			}
    			modify(c[i], -1);
    			//bst[c[i]] = 0;
    			printf("%lld %lld
    ", ans1, ans2);
    		}
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    IIS调试技术之 Debug Diagnostic (调试诊断)
    其实,你什么都不用怕
    应用程序出现挂死,.NET Runtime at IP 791F7E06 (79140000) with exit code 80131506.
    LR_问题_如何将场景中的用户设置为百分比形式
    LR_问题_脚本运行时提示没有参数化
    LR_问题_无法打开IE浏览器、监视服务器资源
    LR_问题_运行场景时提示scripts you are running in invalid
    收集好用的在线调试工具
    es2015 解构赋值
    shim和polyfill
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/15076198.html
Copyright © 2011-2022 走看看