zoukankan      html  css  js  c++  java
  • [BZOJ 3531] [Sdoi2014] 旅行 【离线+LCT】

    题目链接:BZOJ - 3531

    题目分析

    题目询问一条路径上的信息时,每次询问有某种特定的文化的点。

    每个点的文化就相当于一种颜色,每次询问一条路径上某种颜色的点的信息。

    可以使用离线算法, 类似于“郁闷的小 J ” 那道题目。将各种操作和询问按照颜色为第一关键字,时间为第二关键字排序。

    那么修改颜色的操作就相当于在原颜色中是删点,在新颜色中是加点。

    处理完一种颜色的操作后,要将这个颜色的点都做一次删除操作,这样,对于处理下一种颜色,树就又是空的了。

    这种题,思考的时候有点晕,写代码的时候非常愉悦。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    inline void Read(int &Num)
    {
    	char c = getchar();
    	bool Neg = false;
    	while (c < '0' || c > '9')
    	{
    		if (c == '-') Neg = true;
    		c = getchar();
    	}
    	Num = c - '0'; c = getchar();
    	while (c >= '0' && c <= '9')
    	{
    		Num = Num * 10 + c - '0';
    		c = getchar();
    	}
    	if (Neg) Num = -Num;
    }
    
    inline int gmin(int a, int b) {return a < b ? a : b;}
    inline int gmax(int a, int b) {return a > b ? a : b;}
    
    const int MaxN = 100000 + 5, MaxM = 100000 + 5, INF = 999999999;
    
    int n, m, QTop, ATot;
    int W[MaxN], C[MaxN], WT[MaxN], CT[MaxN], Ans[MaxM], Father[MaxN], T[MaxN], Sum[MaxN], Max[MaxN], Son[MaxN][2];
    
    bool isRoot[MaxN], Rev[MaxN];
    
    struct Edge
    {
    	int v;
    	Edge *Next;
    } E[MaxN * 2], *P = E, *Point[MaxN];
    
    inline void AddEdge(int x, int y)
    {
    	++P; P -> v = y;
    	P -> Next = Point[x]; Point[x] = P;
    }
    
    struct ES
    {
    	int Type, Col, Pos, Num, x, y, TL, AIdx; 
    	/*
    		TypeList:
    			1 : Change City-Pos to Num
    			2 : Qsum of the path(x, y)
    			3 : Qmax of the path(x, y)
    	*/
    } Q[MaxN * 2 + MaxM * 2];
    
    inline bool Cmp(ES e1, ES e2)
    {
    	if (e1.Col != e2.Col) return e1.Col < e2.Col;
    	return e1.TL < e2.TL;
    }
    
    queue<int> Qe;
     
    void BFS()
    {
    	while (!Qe.empty()) Qe.pop();
    	Qe.push(1); Father[1] = 0;
    	int x;
    	while (!Qe.empty()) 
    	{
    		x = Qe.front(); Qe.pop();
    		for (Edge *j = Point[x]; j; j = j -> Next)
    		{
    			if (j -> v == Father[x]) continue;
    			Father[j -> v] = x;
    			Qe.push(j -> v);
    		}
    	}
    }
    
    /************************ LCT Start ****************************/
    
    inline void Update(int x)
    {
    	Sum[x] = Sum[Son[x][0]] + Sum[Son[x][1]] + T[x];
    	Max[x] = gmax(T[x], gmax(Max[Son[x][0]], Max[Son[x][1]]));
    }
    
    inline void Reverse(int x)
    {
    	Rev[x] = !Rev[x];
    	swap(Son[x][0], Son[x][1]);
    }
    
    inline void PushDown(int x)
    {
    	if (!Rev[x]) return;
    	Rev[x] = false;
    	if (Son[x][0]) Reverse(Son[x][0]);
    	if (Son[x][1]) Reverse(Son[x][1]);
    }
    
    inline int GetDir(int x) {return x == Son[Father[x]][0] ? 0 : 1;}
    
    void Rotate(int x)
    {
    	int y = Father[x], f = GetDir(x) ^ 1;
    	PushDown(y); PushDown(x);
    	if (isRoot[y])
    	{
    		isRoot[y] = false;
    		isRoot[x] = true;
    	}
    	else Son[Father[y]][GetDir(y)] = x;
    	Father[x] = Father[y];
    	Son[y][f ^ 1] = Son[x][f];
    	if (Son[x][f]) Father[Son[x][f]] = y;
    	Son[x][f] = y; Father[y] = x;
    	Update(y); Update(x);
    }
    
    void Splay(int x)
    {
    	int y;
    	while (!isRoot[x])
    	{
    		y = Father[x];
    		if (isRoot[y])
    		{
    			Rotate(x);
    			break;
    		}
    		if (GetDir(x) == GetDir(y)) Rotate(y);
    		else Rotate(x);
    		Rotate(x);
    	}
    }
    
    inline int Access(int x)
    {
    	int y = 0;
    	while (x != 0)
    	{
    		Splay(x);
    		PushDown(x);
    		if (Son[x][1]) isRoot[Son[x][1]] = true;
    		Son[x][1] = y;
    		if (y) isRoot[y] = false;
    		Update(x);
    		y = x;
    		x = Father[x];
    	}
    	return y;
    }
    
    inline void Make_Root(int x)
    {
    	int t = Access(x);
    	Reverse(t);
    }
    
    /************************ LCT End ****************************/
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; ++i)
    	{
    		Read(W[i]); Read(C[i]);
    		WT[i] = W[i]; CT[i] = C[i];
    	}
    	int a, b;
    	for (int i = 1; i <= n - 1; ++i)
    	{
    		Read(a); Read(b);
    		AddEdge(a, b); AddEdge(b, a);
    	}
    	char Str[5];
    	for (int i = 1; i <= n; ++i)
    	{
    		++QTop; Q[QTop].TL = 0; Q[QTop].Col = CT[i];
    		Q[QTop].Type = 1; Q[QTop].Pos = i; Q[QTop].Num = WT[i];
    	}
    	for (int i = 1; i <= m; ++i)
    	{
    		scanf("%s", Str);
    		Read(a); Read(b);
    		if (strcmp(Str, "CC") == 0)
    		{
    			++QTop; Q[QTop].TL = i; Q[QTop].Col = CT[a];
    			Q[QTop].Type = 1; Q[QTop].Pos = a; Q[QTop].Num = 0;
    			++QTop; Q[QTop].TL = i; Q[QTop].Col = b;
    			Q[QTop].Type = 1; Q[QTop].Pos = a; Q[QTop].Num = WT[a];
    			CT[a] = b;		
    		}
    		else if (strcmp(Str, "CW") == 0)
    		{
    			++QTop; Q[QTop].TL = i; Q[QTop].Col = CT[a];
    			Q[QTop].Type = 1; Q[QTop].Pos = a; Q[QTop].Num = b;
    			WT[a] = b;
    		}
    		else if (strcmp(Str, "QS") == 0)
    		{
    			++QTop; Q[QTop].TL = i; Q[QTop].Col = CT[a];
    			Q[QTop].Type = 2; Q[QTop].x = a; Q[QTop].y = b; Q[QTop].AIdx = ++ATot;
    		}
    		else if (strcmp(Str, "QM") == 0)
    		{
    			++QTop; Q[QTop].TL = i; Q[QTop].Col = CT[a];
    			Q[QTop].Type = 3; Q[QTop].x = a; Q[QTop].y = b; Q[QTop].AIdx = ++ATot;
    		}
    	}
    	for (int i = 1; i <= n; ++i)
    	{
    		++QTop; Q[QTop].TL = INF; Q[QTop].Col = CT[i];
    		Q[QTop].Type = 1; Q[QTop].Pos = i; Q[QTop].Num = 0;
    	}
    	sort(Q + 1, Q + QTop + 1, Cmp);
    	BFS();
    	for (int i = 1; i <= n; ++i)	
    	{
    		isRoot[i] = true; Rev[i] = false;
    		T[i] = 0; Max[i] = 0; Sum[i] = 0;
    	}
    	int t;
    	for (int i = 1; i <= QTop; ++i)
    	{
    		if (Q[i].Type == 1)
    		{
    			Splay(Q[i].Pos);
    			T[Q[i].Pos] = Q[i].Num;
    			Update(Q[i].Pos);
    		}
    		else
    		{
    			Make_Root(Q[i].x);
    			t = Access(Q[i].y);
    			if (Q[i].Type == 2) Ans[Q[i].AIdx] = Sum[t];
    			else Ans[Q[i].AIdx] = Max[t];	
    		}
    	}
    	for (int i = 1; i <= ATot; ++i) printf("%d
    ", Ans[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    1062 Talent and Virtue (25 分)
    1083 List Grades (25 分)
    1149 Dangerous Goods Packaging (25 分)
    1121 Damn Single (25 分)
    1120 Friend Numbers (20 分)
    1084 Broken Keyboard (20 分)
    1092 To Buy or Not to Buy (20 分)
    数组与链表
    二叉树
    时间复杂度与空间复杂度
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4456756.html
Copyright © 2011-2022 走看看