【CodeForces】343D Water tree (线段树好题!还未弄懂)

/*

此题的方法除了用线段树求子树,通过标记父亲,更新儿子的方法,来更新祖先,学习了。
对于建树的方法由于并没有说明父亲与儿子的顺序,所以需要通过两次添加。
并且pre变量可以获得父亲的位置,还未弄懂!
*/
#define _CRT_SECURE_NO_WARNINGS
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 500005
#define ls rt<<1
#define rs ls|1
#define m (l+r)>>1
int sum[MAX << 2];
int col[MAX << 2];
int fa[MAX << 2];
int head[MAX];
int num;
int time;

struct tree
{
    int v, next;
}edg[MAX<<2];

struct f
{
    int s, e;
}s[MAX];

void addedge(int a, int b)
{
    edg[num].v = b;
    edg[num].next = head[a];
    head[a] = num++;
}

void dfs(int a, int pre)
{
    fa[a] = pre;
    s[a].s = ++time;
    for (int i = head[a]; i != -1; i = edg[i].next)
    {
        if (edg[i].v == pre)continue;
        dfs(edg[i].v, a);
    }
    s[a].e = time;
}

void uprt(int rt)
{
    sum[rt] = sum[ls] && sum[rs];
}

void uprt2(int rt)
{
    if (col[rt] == 1)
    {
        sum[rs] = sum[ls] = col[rt];
        col[rs] = col[ls] = col[rt];
        col[rt] = -1;
    }
}
void updata(int L, int R, int c, int l, int r, int rt)
{
    if (L <= l&&r <= R)
    {
        col[rt] = c;
        sum[rt] = c;
        return;
    }
    uprt2(rt);
    int mid = m;
    if (L <= mid)
        updata(L, R, c, l, mid, ls);
    if (mid < R)
        updata(L, R, c, mid + 1, r, rs);
    uprt(rt);
}

void updata(int q, int l, int r, int rt)
{
    if (l == r)
    {
        sum[rt] = 0;
        return;
    }
    uprt2(rt);
    int mid = m;
    if (q <= mid)
        updata(q, l, mid, ls);
    if (mid < q)
        updata(q, mid + 1, r, rs);
    uprt(rt);
}
int query(int L,int R, int l, int r, int rt)
{

    if (L<=l&&r<=R)
        return sum[rt];
    uprt2(rt);
    int mid = m;
    int a = 0x7fff, b = 0x7fff;
        if(L<=mid)a=query(L,R, l, mid, ls);
        if(R>mid)b=query(L,R, mid + 1, r, rs);
        return min(a, b);
}

int main()
{
    int n;
    while (~scanf("%d",&n))
    {
        num = 0;
        time = 0;
        memset(head, -1, sizeof(head));
        int a, b;
        memset(sum, 0, sizeof(sum));
        memset(col, -1, sizeof(col));
        for (int i = 1; i < n; i++)
        {
            scanf("%d%d", &a, &b);
            addedge(a, b);
            addedge(b, a);
        }
        dfs(1, -1);
        int c;
        int t;
        cin >> t;
        bool tg = true;
        while (t--)
        {
            scanf("%d%d", &c, &a);
            if (c == 1)
            {
                //这个操作的作用是由于要将一个点变为1,那么假如这个点原来是0的话,那么他的祖先都是0
                //但是没办法一下子全部修改祖先,所以就只能够在更新一个0的节点为1的时候将他的父亲变为0,这样就可以保持下去
                //绝妙!!
                if (!query(s[a].s, s[a].e, 1, n, 1) && fa[a] != -1)
                {

                    updata(s[fa[a]].s, 1, n, 1);
                }
                updata(s[a].s, s[a].e, 1, 1, n, 1);
            }
            else if (c == 2)
            {
                updata(s[a].s, 1, n, 1);
            }
            else if (c == 3)
            {

                printf("%d\n", query(s[a].s, s[a].e, 1, n, 1));
            }
        }
    }
}
时间: 2024-10-12 15:57:59

【CodeForces】343D Water tree (线段树好题!还未弄懂)的相关文章

codeforces 343D Water Tree 树链剖分 dfs序 线段树 set

题目链接 这道题主要是要考虑到同一棵子树中dfs序是连续的 然后我就直接上树剖了... 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=600005; 4 5 struct Node 6 { 7 int l,r; 8 int value; 9 void init() 10 { 11 l=r=value=0; 12 } 13 }tree[4*MAXN]; 14 vector<int>nei[MAXN]

Codeforces 343D Water Tree & 树链剖分教程

原题链接 题目大意 给定一棵根为1,初始时所有节点值为0的树,进行以下三个操作: 将以某点为根的子树节点值都变为1 将某个节点及其祖先的值都变为0 *询问某个节点的值 解题思路 这是一道裸的树链剖分题.下面详细地介绍一下树链剖分. 树链剖分预备知识: 线段树.DFS序 树链剖分想法|起源 首先,如果一棵树退化成一条链,那么它会有非常好的性质.我们可以用线段树等数据结构来维护相关操作,使得效率更高.那么我们考虑一般的树,它是否能被分成一些链,使它们也能更高效地进行某些操作? 算法流程 以下以点带权

Codeforces 343D Water Tree(DFS序+线段树+技巧)

题目链接:http://codeforces.com/problemset/problem/343/D 题目: Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a reservoir which can be either empty or filled with water. The vertices of the tree are numbered f

CodeForces 343D water tree(树链剖分)

Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a reservoir which can be either empty or filled with water. The vertices of the tree are numbered from 1 to n with the root at vertex 1. For each vertex, t

Codeforces 343D Water Tree

题意简述 维护一棵树,支持以下操作: 0 v:将以v为跟的子树赋值为1 1 v:将v到根节点的路径赋值为0 2 v:询问v的值 题解思路 树剖+珂朵莉树 代码 #include <set> #include <cstdio> #define IT std::set<Node>::iterator const int N=500005; int n,q,u,v,opt,x,cnt; int h[N],to[N<<1],nxt[N<<1]; int

Codeforces 383C Propagating tree, 线段树, 黑白染色思想

按深度染色,奇深度的点存反权值. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 vector <int> g[500005]; 5 int t1,t2,t3,seq[500005],a[1000005],s[500005],vis[500005],ind,n,m,src[500005],frm[500005],dep[500005]; 6 7 void dfs(int p) { 8 vis[p]=1; 9 frm[p]=

[Codeforces 1295E]Permutation Separation(线段树+贪心)

[Codeforces 1295E]Permutation Separation(线段树+贪心) 题面 给出一个排列\(p_1,p_2,...p_n\).初始时你需要选择一个位置把排列分成左右两个.然后在两个序列间移动元素使得左边序列的所有元素都比右边的所有元素小.给出每个元素\(p_i\)从一个序列移动到另一个序列的代价\(a_i\). 分析 显然最后得到的序列是小的数在一边,大的数在另一边.设从值为\(i\)的元素处分开之后移动代价为\(ans_i\). 一开始假设所有数都移到右边序列,那么

Codeforces Round #393 (Div. 2) (8VC Venture Cup 2017 - Final Round Div. 2 Edition) E - Nikita and stack 线段树好题

http://codeforces.com/contest/760/problem/E 题目大意:现在对栈有m个操作,但是顺序是乱的,现在每输入一个操作要求你输出当前的栈顶, 注意,已有操作要按它们的时间顺序进行. 思路:线段树好题啊啊,我们把push当成+1, pop当成-1,按操作的位置建立线段树,那么如何 寻找栈顶呢,我们计算每个点的后缀,栈顶就是下标最大的>0的后缀,我们拿后缀建立线段树, 剩下的就是区间加减法,和求区间最大值啦. #include<bits/stdc++.h>

HDU 4027 Can you answer these queries? 线段树裸题

题意: 给定2个操作 0.把区间的每个数sqrt 2.求和 因为每个数的sqrt次数很少,所以直接更新到底,用个标记表示是否更新完全(即区间内的数字只有0,1就不用再更新了) #include<stdio.h> #include<iostream> #include<algorithm> #include<vector> #include<cmath> #include<queue> #include<set> #incl