JOI春合宿2013 Day2-3 Spy

解説みて解いた.問題が木だったらとりあえずEuler-Tourを使えないか考えるとよさそう.
二次元にして長方形を塗るという考え方は頭がいい.

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 2010, MAXM = 500000;
typedef pair<int,int> P;
int N,M;
vector<int> G[2][MAXN]; //部下の頂点番号
P vs[2][MAXN]; //その頂点がEuler Tour上で初めて現れる場所と最後に現れる場所
int boss[2];
int a[2*MAXN][2*MAXN];

void euler_tour(int g, int v, int *k){
	vs[g][v].first = vs[g][v].second = *k;
	(*k)++;
	for(int i = 0; i < G[g][v].size(); i++){
		int u = G[g][v][i];
		euler_tour(g, u, k);
		vs[g][v].second = *k;
		(*k)++;
	}
}
void read(){
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;i++){
		int a, b;
		scanf("%d %d", &a, &b);
		if(a == 0)
			boss[0] = i;
		else
			G[0][a].push_back(i);
		if(b == 0)
			boss[1] = i;
		else
			G[1][b].push_back(i);
	}
	int k = 0;
	euler_tour(0,boss[0],&k);
	k = 0;
	euler_tour(1,boss[1],&k);
	for(int i=0;i<M;i++){
		int x, y;
		scanf("%d %d", &x, &y);
		a[vs[0][x].first     ][vs[1][y].first     ]++;
		a[vs[0][x].second + 1][vs[1][y].first     ]--;
		a[vs[0][x].first     ][vs[1][y].second + 1]--;
		a[vs[0][x].second + 1][vs[1][y].second + 1]++;
	}
}
int main(){
	read();
	for(int i = 0; i <= 2*N; i++)
		for(int j = 1; j <= 2*N; j++)
			a[i][j]+=a[i][j-1];
	for(int i = 1; i <= 2*N; i++)
		for(int j = 0; j <= 2*N; j++)
			a[i][j]+=a[i-1][j];
	for(int i = 1; i <= N; i++){
		printf("%d\n", a[vs[0][i].first][vs[1][i].first]);
	}
}