Little Devil I

题面:从前有一个国家,国家里面的城市是树形结构的。这个国家的国王是个萝莉控,爱上了一个小恶魔。

小恶魔喜欢制造混乱,经常让国王修改城市之间的道路系统。每条道路有两种颜色,黑与白。

修改有两种,一是把城市a和b之间的道路全部翻转颜色,二是把城市a和b之间道路的相邻路翻色。

国王的萝莉女儿,WJMZBMR很关心国家道路状况,她会询问a和b之间的道路有多少是黑色的。

一开始所有道路都是白色。

分析:

第一种操作就是最简单的树链剖分。

第二种操作如果要用树链剖分,需要仔细思考。

首先,还是只能更新那logN条链,可以想到在链上打标记来表示更新了周围的点。这样做是否可行呢?

在路径的重链上,中间的点是不变的,被标记了两次,这是合法的。

考虑询问。在询问的时候,存在两个问题,1.重链的点很多,2.某个点的度数很多。这将导致复杂度变成O(n)。

需要修改标记的含义,对于2,一条边只需要一个标记的点就够了,最适合的点是这条边的父结点。

对于1,重链上中间的点是不必标记的。

综上,在一个父节点打标记表示修改了它的孩子轻边。剩下O(logN)个端点特殊处理一下,复杂不会退化。

标记区间更新点,翻转区间更新边,这个操作可以用线段树完成。(边的id用它的子结点编号,这个写着的时候挺容易出错的。

复杂度O(Qlognlogn)

/*********************************************************
*            ------------------                          *
*   author AbyssFish                                     *
**********************************************************/
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<numeric>
#include<climits>
using namespace std;

const int maxn = 1e5+5;

int hd[maxn], nx[maxn<<1], to[maxn<<1], ec;
void add_edge(int u,int v)
{
    nx[ec] = hd[u];
    to[ec] = v;
    hd[u] = ec++;
}
void init_g(int n){ memset(hd+1,0xff,n*sizeof(int)); ec = 0; }
#define eachedge int i = hd[u]; ~i; i = nx[i]
#define ifvalid int v = to[i]; if(v == fa[u]) continue;

int n;

/*----------------------------------------*/

int fa[maxn];
int tr_sz[maxn];
int top[maxn];
int son[maxn];
int dep[maxn];
int id[maxn];
int id_cnt;

// id[0] = tr_sz[0] = 0
void dfs(int u,int f = 0,int d = 0)
{
    dep[u] = d;
    son[u] = 0;
    fa[u] = f;
    tr_sz[u] = 1;
    for(eachedge){
        ifvalid
        dfs(v,u,d+1);
        tr_sz[u] += tr_sz[v];
        if(tr_sz[v] > tr_sz[son[u]]){
            son[u] = v;
        }
    }
}

void sub_dv(int u,int tp)
{
    top[u] = tp;
    id[u] = ++id_cnt;
    if(son[u]) sub_dv(son[u],tp);
    for(eachedge){
        ifvalid
        if(v != son[u])
            sub_dv(v,v);
    }
}

/*----------------------------------------*/

#define para int o = 1,int l = 1,int r = n
#define lo (o<<1)
#define ro (o<<1|1)
#define Tvar int md = (l+r)>>1;
#define lsn lo,l,md
#define rsn ro,md+1,r
#define insd ql<=l&&r<=qr
#define qpara int ql,int qr,para
#define qlsn  ql, qr,lsn
#define qrsn  ql, qr,rsn
const int ST_SIZE = 1<<18;

int flp[ST_SIZE], sum[ST_SIZE]; //edge
int flg[ST_SIZE];//vertex

void build(para)
{
    sum[o] = flp[o] = flg[o] = 0;
    if(l < r){
        Tvar
        build(lsn);
        build(rsn);
    }
}

inline void sink(int o,int tot)
{
    flp[o] ^= 1;
    sum[o] = tot - sum[o];
}

inline void dwn_flp(int o,int l,int r)
{
    if(flp[o]){
        Tvar
        sink(lo,md+1-l);
        sink(ro,r-md);
        flp[o] = 0;
    }
}

void update_flp(qpara)
{
    if(insd){
        sink(o,r+1-l);
    }
    else {
        Tvar
        dwn_flp(o,l,r);
        if(ql <= md) update_flp(qlsn);
        if(qr > md) update_flp(qrsn);
        sum[o] = sum[lo] + sum[ro];
    }
}

int q_flp_sum(qpara)
{
    if(insd) return sum[o];
    else {
        Tvar
        dwn_flp(o,l,r);
        int re = 0;
        if(ql <= md) re += q_flp_sum(qlsn);
        if(qr > md) re += q_flp_sum(qrsn);
        return re;
    }
}

/*----------------------------------------*/

int q_flg(int qpos, para)
{
    if(l == r) return flg[o];
    else {
        Tvar
        return flg[o]^(qpos <= md ? q_flg(qpos,lsn) : q_flg(qpos,rsn));
    }
}

void update_flg(qpara)
{
    if(insd) flg[o] ^= 1;
    else {
        Tvar
        if(ql <= md) update_flg(qlsn);
        if(qr > md) update_flg(qrsn);
    }
}

/*----------------------------------------*/

void rvPath(int a,int b)
{
    int p = top[a], q = top[b];
    while(p != q){
        if(dep[p] < dep[q]) swap(a,b), swap(p,q);
        update_flp(id[p],id[a]);
        p = top[a = fa[p]];
    }

    if(a != b){
        if(dep[a] > dep[b]) swap(a,b);
        update_flp(id[son[a]],id[b]);
    }
}

void rvAdj(int a,int b)
{
    int p = top[a], q = top[b];
    while(p != q){
        if(dep[p] < dep[q]) swap(a,b), swap(p,q);
        update_flg(id[p],id[a]);
        update_flp(id[p],id[p]);
        if(son[a]) {
            update_flp(id[son[a]],id[son[a]]);
        }
        p = top[a = fa[p]];
    }
    if(dep[a] > dep[b]) swap(a,b);
    update_flg(id[a],id[b]);

    update_flp(id[a],id[a]);

    if(son[b]) {
        update_flp(id[son[b]],id[son[b]]);
    }
}

int query(int a,int b)
{
    int re = 0;
    int p = top[a], q = top[b];
    while(p != q){
        if(dep[p] < dep[q]) swap(a,b), swap(p,q);
        if(a != p){
            re += q_flp_sum(id[son[p]],id[a]);
        }
        re += q_flg(id[fa[p]]) ^ q_flp_sum(id[p],id[p]);
        p = top[a = fa[p]];
    }
    if(a != b){
        if(dep[a] > dep[b]) swap(a,b);
        re += q_flp_sum(id[son[a]],id[b]);
    }
    return re;
}

/*----------------------------------------*/

void init()
{
    scanf("%d",&n);
    init_g(n);
    int a,b;
    for(int i = 1; i < n; i++){
        scanf("%d%d",&a,&b);
        add_edge(a,b); add_edge(b,a);
    }
}

void solve()
{
    id_cnt = 0;
    dfs(1);
    sub_dv(1,1);

    build();

    int Q;
    scanf("%d",&Q);
    int t,a,b;
    while(Q--){
        scanf("%d%d%d",&t,&a,&b);
        if(t == 1) rvPath(a,b);
        else if(t == 2) rvAdj(a,b);
        else if(t == 3) printf("%d\n", query(a,b));
    }
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    //cout<<log2(maxn);
    int T;
    scanf("%d",&T);
    while(T--){
        init();
        solve();
    }
    return 0;
}
时间: 2024-10-06 06:20:14

Little Devil I的相关文章

越狱Season 1-Episode 6: Riots, Drills and the Devil: Part 1

Season 1, Episode 6: Riots, Drills and the Devil: Part 1 - Diamond: Just a few more rides. 就再多玩几次吧 Oh, great! Great! 噢太棒了! Then you have to wrap it up. wrap: 包,裹 玩好了就该走了 -Kellerman: Oh, Adam's getting bigger, huh? 噢 Adam看上去长大了点 Ten. Hmm 十岁嗯? - Diamon

越狱Season 1-Episode 7: Riots, Drills and the Devil: Part 2

Season 1, Episode 7: Riots, Drills and the Devil: Part 2 -Pope: Belick, get those guys in line guy: (男)人,家伙 Belick 让那些家伙站好 -Berwick: get them the information information: 通知 叫他们排好队 go on back in? 我们进去吗? -Pope: Not yet 现在还不行 we cut the water about an

HDU 4897 Little Devil I

_(:3 ⌒?)_ 调我半天,还是记录下吧. 用轻重链可解决此题. 用轻重链的方式给点重新编号后,建两棵线段树,一棵(sumTree)用于记录路径修改,另外一棵(markTree)用于记录邻边修改的点. 然后维护下两棵树即可. 注意,markTree修改时,要在sumTree上修改第一个点和最后一个点对应的重边,若修改的顶点为连接轻链的点,则sumTree对应边不修改. #include<cstdio> #include<cstring> #include<algorithm

Does Deep Learning Come from the Devil?

Does Deep Learning Come from the Devil? Deep learning has revolutionized computer vision and natural language processing. Yet the mathematics explaining its success remains elusive. At the Yandex conference on machine learning prospects and applicati

DevIL编译过程出现的 “error C2001: newline in constant” 解决方法(VS2015)

在编译图像库DevIL过程中出现 "error C2001: newline in constant" . 这是由于源码文件的编码方式为 UTF-8无BOM格式,修改编码方式为UTF-8标准格式(Notepad++).

【BZOJ3864】Hero meet devil DP套DP

[BZOJ3864]Hero meet devil Description There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in lo

[hdu 4899]14年多校第四场C Hero meet devil 状压DP

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 122    Accepted Submission(s): 49 Problem Description There is an old country and the king fell in love with a devil. The devil always asks th

hdu 4897 Little Devil I(树链剖分+线段树)

题目链接:hdu 4897 Little Devil I 题目大意:给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一个节点在路径上) 3 u v:查询u到v路径上有多少个黑色边 解题思路:树链剖分,用两个线段W和L维护,W对应的是每条的黑白情况,L表示的是每个节点的相邻边翻转情况 (对于轻链而言,重链直接在W上修改) 对于1操作,即为普通的树链剖分,直接在W上修改即可.

hdu 4857 Little Devil I

http://acm.hdu.edu.cn/showproblem.php?pid=4897 题意:给你一棵树,边的颜色要么为白色,要么为黑色,初始每条边为白色,有三种操作 1.将u-v链上面的所有边的颜色翻转 2.将u-v链上面所有邻接的边翻转(边上只有一个点在链上面) 3.询问u->v上面有多少黑色的边 树链剖分,线段树维护4个信息: 按dfs序建立线段树后,如果线段树内节点的区间为[l,r],则此节点维护树上dfs序[l,r]内的父边的信息 父边指 点与父节点之间的边 sum0:节点的父边

BZOJ3864 : Hero meet devil

考虑计算LCS的DP过程,设f[i][j]表示T串的前i项与S串的前j项的LCS,则 若T[i]==S[j],则f[i][j]=f[i-1][j-1]+1 否则f[i][j]=max(f[i-1][j],f[i][j-1]) 对于固定的i,f[i][j]只可能为f[i][j-1]或f[i][j-1]+1,把这个差值用二进制表示成状态. 先预处理出每个状态后面加了一个字符后会到达什么状态,然后进行状压DP即可. 时间复杂度$O(m2^n)$. #include<cstdio> #include&