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;
    }
    

      

  • 相关阅读:
    linux上的工具或软件
    百度分享插件怎么取消鼠标放在图片上出现的分享条
    常用的Lambda表达式
    IDEA安装使用Lombok插件
    Spring cloud Eureka错误锦集(二)
    Spring cloud Eureka错误锦集(一)
    Navicat破解
    手动添加jar包到本地仓库
    Markdown常用语法
    Java中的位运算符
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4456756.html
Copyright © 2011-2022 走看看