@uoj - 435 @ 2018] [Team work Simple Tree


@description@

There is a rooted tree, the root of 1, point a little right.
There are m operations, there are three kinds of operations:
. 1 xyw, little to the right in the x-y path plus w (where ±. 1 = W);
2 XY, on the path to ask x y is the number of bit right> 0;
3 x, x interrogation points in the sub-tree's how much a little bit right> 0.

Input format
of the first row of three numbers n, m, T, denotes the number of tree nodes, the number of operations, and is encrypted.
Next, n-1 lines, each line number 2 xy, indicates there is an edge between the node x and y.
Next, a line number n, the i-th point represents the initial weight of node i.
Next m lines of formatted as described in the subject.
If T = 1, then this row is read into each of m x, y XOR last_ans need to get real inputs, wherein the answer to the question on the operation of the primary last_ans expressed, if there is no previous query operation is zero.

Output format
represents the answer to each inquiry operation, the output line.

A sample
INPUT
. 5. 5 0
. 1 2
. 1. 3
. 3. 4
. 3. 5
. 1 0 0 0 0
2 2. 5
. 3. 3
. 1. 5. 1 2
2 2. 5
. 3. 3
Output
. 1
0
. 4
2

Limitations and Conventions
for all data, 1≤n≤10 ^ 5,1≤m≤10 ^ 5, -10 ^ 9≤ right point ≤10 ^ 9.

@solution@

You may wish to consider the case of chain.

Range range of modifications to the query, in addition to the block, at least I did not think of other methods.
When the modified block tag, sorting reconstructed discrete pieces violence; query block half, discrete pieces violence.
Get a \ (O (n \ sqrt { n} \ log n) \) algorithm.

As for the tree. Tree block? Heard, what things ah.
We can turn into a tree split log chain disjoint intervals modify the query.
Even a violent obtained not as the \ (O (n \ sqrt { n} \ log ^ 2 n) \) algorithm.

Do not panic, we try to optimize it, the ability to remove the log block itself.
A spatial approach using consume large bucket. Note that when the range of the absolute value | ai |> m, the number of portions is of no use. So we can be reduced to the range between -m ~ m.
Then you can start for each block of size 2 * m a bucket. ± 1 each block, the change amount of the whole block can answer O (1) count.
This question may have to open short int will not be space card.

Another approach is to directly optimize the original approach.
Sorting can be modified zone and has not been modified in the first split range, change, and then merge. There is no log of existence.
Maintenance of a calculated amount of change answers pointer convenient piece changes. In order to do O (1) move the pointer, you need a number to skip all the same value, then maintained at the same value as the leftmost and rightmost.

This optimization has become \ (O (n-\ n-sqrt {} \ log n-) \) . But still a little mysterious, we'll optimize it.
Noting the split tree chains turn into one operation log a disjoint interval operation, thus relates to a maximum of \ (O (\ sqrt {n }) \) th block, and the discrete pieces may have \ (O (\ log n) \) months.
Thus the complexity of the discrete pieces is larger than a block. We stress that the small block into \ (O (\ sqrt {n \ log n}) \) blocks, may be effectively equalized in complexity \ (O (\ sqrt {n \ log n}) \) .

@accepted code@

//用桶的方法 AC 的
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100002;
const int BLOCK = 105;
struct edge{
    int to; edge *nxt;
}edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt=&edges[0];
void addedge(int u, int v) {
    edge *p = (++ecnt);
    p->to = v, p->nxt = adj[u], adj[u] = p;
    p = (++ecnt);
    p->to = u, p->nxt = adj[v], adj[v] = p;
}
int siz[MAXN + 5], dep[MAXN + 5], hvy[MAXN + 5], fa[MAXN + 5];
void dfs1(int x, int f) {
    fa[x] = f, siz[x] = 1, dep[x] = dep[f] + 1, hvy[x] = 0;
    for(edge *p=adj[x];p;p=p->nxt) {
        if( p->to == f ) continue;
        dfs1(p->to, x);
        siz[x] += siz[p->to];
        if( siz[p->to] > siz[hvy[x]] )
            hvy[x] = p->to;
    }
}
int top[MAXN + 5], tid[MAXN + 5], dfn[MAXN + 5], dcnt;
void dfs2(int x, int tp) {
    top[x] = tp, tid[x] = (++dcnt), dfn[dcnt] = x;
    if( !hvy[x] ) return ;
    dfs2(hvy[x], tp);
    for(edge *p=adj[x];p;p=p->nxt)
        if( p->to != fa[x] && p->to != hvy[x] )
            dfs2(p->to, p->to);
}
int n, m, T;
int a[MAXN + 5], id[MAXN + 5];
int l[MAXN + 5], r[MAXN + 5], tg[MAXN + 5], res[MAXN + 5];
short int cnt[1000][2*MAXN + 5];
void insert(int k, int x) {cnt[x][k]++; if( k > tg[x] ) res[x]++;}
void erase(int k, int x) {cnt[x][k]--; if( k > tg[x]) res[x]--;}
void add(int x) {res[x] += cnt[x][tg[x]], tg[x]--;}
void remove(int x) {tg[x]++, res[x] -= cnt[x][tg[x]];}
void build() {
    int bcnt = 0;
    for(int i=1;i<=n;i++) {
        if( (i - 1) % BLOCK == 0 )
            bcnt++, l[bcnt] = i, tg[bcnt] = MAXN, res[bcnt] = 0;
        r[bcnt] = i, insert(a[dfn[i]], id[i] = bcnt);
    }
}
void update(int &x) {
    if( x < 0 ) x = 0;
    if( x > 2*MAXN ) x = 2*MAXN;
}
void Amodify(int le, int ri, int w) {
    if( id[le] == id[ri] ) {
        int p = id[le];
        for(int i=le;i<=ri;i++) {
            erase(a[dfn[i]], p);
            a[dfn[i]] += w, update(a[dfn[i]]);
            insert(a[dfn[i]], p);
        }
    }
    else {
        int p = id[le], q = id[ri];
        for(int i=le;i<=r[p];i++) {
            erase(a[dfn[i]], p);
            a[dfn[i]] += w, update(a[dfn[i]]);
            insert(a[dfn[i]], p);
        }
        for(int i=p+1;i<=q-1;i++)
            ( w == 1 ) ? add(i) : remove(i);
        for(int i=l[q];i<=ri;i++) {
            erase(a[dfn[i]], q);
            a[dfn[i]] += w, update(a[dfn[i]]);
            insert(a[dfn[i]], q);
        }
    }
}
int Aquery(int le, int ri) {
    int ret = 0;
    if( id[le] == id[ri] ) {
        int p = id[le];
        for(int i=le;i<=ri;i++)
            ret += (a[dfn[i]] > tg[p]);
    }
    else {
        int p = id[le], q = id[ri];
        for(int i=le;i<=r[p];i++)
            ret += (a[dfn[i]] > tg[p]);
        for(int i=p+1;i<=q-1;i++)
            ret += res[i];
        for(int i=l[q];i<=ri;i++) 
            ret += (a[dfn[i]] > tg[q]);
    }
    return ret;
}
void modify(int x, int y, int w) {
    while( top[x] != top[y] ) {
        if( dep[top[x]] < dep[top[y]] ) swap(x, y);
        Amodify(tid[top[x]], tid[x], w);
        x = fa[top[x]];
    }
    if( dep[x] < dep[y] ) swap(x, y);
    Amodify(tid[y], tid[x], w);
}
int query(int x, int y) {
    int ret = 0;
    while( top[x] != top[y] ) {
        if( dep[top[x]] < dep[top[y]] ) swap(x, y);
        ret += Aquery(tid[top[x]], tid[x]);
        x = fa[top[x]];
    }
    if( dep[x] < dep[y] ) swap(x, y);
    ret += Aquery(tid[y], tid[x]);
    return ret;
}
int query(int x) {
    return Aquery(tid[x], tid[x] + siz[x] - 1);
}
int main() {
    scanf("%d%d%d", &n, &m, &T);
    for(int i=1;i<n;i++) {
        int x, y; scanf("%d%d", &x, &y);
        addedge(x, y);
    }
    for(int i=1;i<=n;i++)
        scanf("%d", &a[i]), a[i] += MAXN, update(a[i]);
    dfs1(1, 0), dfs2(1, 1), build();
    int last_ans = 0;
    for(int i=1;i<=m;i++) {
        int op; scanf("%d", &op);
        if( op == 1 ) {
            int x, y, w; scanf("%d%d%d", &x, &y, &w);
            modify(x ^ last_ans, y ^ last_ans, w);
        }
        else if( op == 2 ) {
            int x, y; scanf("%d%d", &x, &y);
            last_ans = query(x ^ last_ans, y ^ last_ans);
            printf("%d\n", last_ans), last_ans *= T;
        }
        else {
            int x; scanf("%d", &x);
            last_ans = query(x ^ last_ans);
            printf("%d\n", last_ans), last_ans *= T;
        }
    }
}

@details@

The method of discovery is finished barrel hack data memory card.
Then huff into reconstruction method, adjusting the afternoon finally passed (my chain tree split if the point number again confused with dfs sequence of numbers I ***).

Then someone told me that short int can live.
. . .

Guess you like

Origin www.cnblogs.com/Tiw-Air-OAO/p/11712604.html