Cod sursa(job #428716)

Utilizator laserbeamBalan Catalin laserbeam Data 29 martie 2010 14:59:18
Problema Atac Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.89 kb
// Catalin Balan
// Mon Mar 29 13:00:55 EEST 2010
// preONI 2004 - atac

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <utility>
#include <bitset>

using namespace std;

#define NMAX 40024
#define CHUNK 8192
#define LogMAX 35

#define FIN "atac.in"
#define FOUT "atac.out"

char g_buf[CHUNK];
int g_p=CHUNK-1;

inline int get()
{

	int x = 0;
	while (g_buf[g_p] < '0' || g_buf[g_p] > '9')
		if (++g_p == CHUNK) fread(g_buf,1,CHUNK,stdin), g_p=0;

	while (g_buf[g_p] >= '0' && g_buf[g_p] <= '9')
	{
		x = x*10 + g_buf[g_p]-'0';
		if (++g_p == CHUNK) fread(g_buf,1,CHUNK,stdin), g_p=0;
	}
	return x;
}

typedef pair<int, int> edg;

vector<edg> G[NMAX];
int nn,m,p;
int LCA[2*NMAX]; // nodurile puse in parcurgerea euleriana
int lvl[2*NMAX]; // adancimile nodurilor in aceeasi parcurgere
int pLCA[NMAX]; // pozitia unui nod in parcurgerea euleriana
int RMQ[2*NMAX][LogMAX]; // RMQ doh... - tin pozitii in lvl, nu valori
bitset<NMAX> viz;
int parents[NMAX][LogMAX]; // parents[i][j] = cine e al 2^j-lea parine al lui i
int costs[NMAX][LogMAX]; // costul desfiintarii drumului intre i si al 2^j-lea parinte al lui i
int n;

// fa parcurgerea euler
void makeLCA( int nod, int &p, int depth)
{
	LCA[p] = nod;
	lvl[p] = depth;
	pLCA[nod] = p;
	++p;
	viz[nod] = true;
	if ( nod != 1 && G[nod].size() == 1) return;
	vector<edg>::iterator it;
	for (it = G[nod].begin(); it != G[nod].end(); ++it)
	{
		if (viz[it->first]) continue;
		costs[it->first][0] = it->second; // astea 2 linii == initializare la makeCosta();
		parents[it->first][0] = nod;
		makeLCA( it->first, p, depth+1 );
		LCA[p] = nod;
		lvl[p] = depth;
		++p;
	}
}

// precalculeaza range minimum querry pe parcurgerea euler
void makeRMQ( int st, int dr )
{
	for (int i = st; i <= dr; ++i)
		RMQ[i][0] = i;
	for (int len = 1; (1<<len) <= dr; ++len)
	{
		int len2 = 1<<(len-1);
		for (int i = st; i <= dr+1-len; ++i)
		{
			RMQ[i][len] = RMQ[i][len-1];
			if ( lvl[ RMQ[i][len] ] > lvl[ RMQ[i+len2][len-1] ])
				RMQ[i][len] = RMQ[i+len2][len-1];
		}
	}
}

// calculeaza parintii si costurile de oridinul 2^j al fiecarui nod
void makeCosts()
{
	parents[0][0] = 0;
	costs[0][0] = 200000; // infinit
	parents[1][0] = 0;
	costs[1][0] = 200000; // infinit
	for (int len = 1; (1<<len) < n; ++len )
	{
		for (int i = 2; i <= n; ++i)
		{
			parents[i][len] = parents[ parents[i][len-1] ][len-1];
			costs[i][len] = min( costs[i][len-1], costs[ parents[i][len-1] ][len-1] );
		}
	}
}

// afla cel mai apropiat bunic al nodurilor cu pozitiile st, si dr in LCA[]
int queryLCA( int st, int dr )
{
	int l = dr-st+1;
	int len;
	for (len = 1; (1<<len) <= l; ++len);
	--len;
//	fprintf(stderr, "\n-- %d %d %d %d --\n", st, dr, len, l);
	int rez = RMQ[st][len];
	if (lvl[ RMQ[st][len] ] > lvl[ RMQ[dr-(1<<len)+1][len] ]) rez = RMQ[dr-(1<<len)+1][len];
	return LCA[rez];	
}

// afla costul minim de a-l taia pe nodul nod de al nth-lea stramos al sau
int getCost( int nod, int nth )
{
	int rez = 200000; // infinit
	int len;
	for (len = 1; (1<<len) <= nth; ++len);
	for (--len; len >= 0; --len)
	{
		if (nth < (1<<len)) continue;
		rez = min(rez, costs[nod][len]);
		nod = parents[nod][len];
		nth -= (1<<len);
	}
	return rez;
}

int main(int argv, char ** argc)
{
	freopen(FIN, "r", stdin);
	freopen(FOUT, "w", stdout);

	n = get();
	m = get();
	p = get();
	for (int i = 2; i <= n; ++i)
	{
		int x = get();
		int z = get();
		G[x].push_back(make_pair(i,z));
		G[i].push_back(make_pair(x,z));
	}
	nn = 1;
	makeLCA(1,nn,1);
	--nn;
	makeRMQ(1,nn);
	makeCosts();

	int X,Y,A,B,C,D;
	X = get();
	Y = get();
	A = get();
	B = get();
	C = get();
	D = get();

/*	for (int i = 1; i <= nn; ++i) fprintf(stderr, "%d ", LCA[i]);
	fprintf(stderr, "\n");
	for (int i = 1; i <= nn; ++i) fprintf(stderr, "%d ", lvl[i]);
	fprintf(stderr, "\n");
	for (int i = 1; i <= n; ++i) fprintf(stderr, "%d ", pLCA[i]);
	fprintf(stderr, "\n\n");
	for (int len = 0; (1<<len) <= nn; ++len)
	{
		for (int i = 1; i <= nn; ++i) fprintf(stderr, "%d ", RMQ[i][len]);
		fprintf(stderr, "\n");
	}
	fprintf(stderr, "\n\n");
	for (int len = 0; (1<<len) <= n; ++len)
	{
		for (int i = 1; i <= n; ++i) fprintf(stderr, "%d ", costs[i][len]);
		fprintf(stderr, "\n");
	}
	fprintf(stderr, "\n\n");
*/	int Xp, Yp, Z;
	for (int i = 1; i <= m; ++i)
	{
		if (X == Y)
		{
			if (i >= m-p+1)
				printf("0\n");
			Xp = (X*A + Y*B)%n + 1;
			Yp = (Y*C)%n + 1;
			Y = Yp; X = Xp;
			continue;
		}
		Xp = X;
		Yp = Y;
		if (pLCA[Yp] < pLCA[Xp]) { int aux = Xp; Xp = Yp; Yp = aux; }
		int tata = queryLCA(pLCA[Xp], pLCA[Yp]); // cine e bunicu
		int dt = lvl[pLCA[tata]]; // adancimea bunicului
		int dx = lvl[pLCA[Xp]]; // adancimea lui X
		int dy = lvl[pLCA[Yp]]; // adancimea lui Y

//		fprintf(stderr, "%d %d %d %d - %d %d = %d %d\n", Xp, Yp, dx-dt, dy-dt, tata, dt, getCost(Xp, dx-dt), getCost(Yp, dy-dt));

	
		Z = min( getCost(Xp, dx-dt), getCost(Yp, dy-dt) );
		if (i >= m-p+1)
			printf("%d\n", Z );
		Xp = (X*A + Y*B)%n + 1;
		Yp = (Y*C + Z*D)%n + 1;
		Y = Yp; X = Xp;

	}
	
	return EXIT_SUCCESS;
}