QTREE[不定期更新]

  我又开新坑啦:QTREE系列.

  刚开始以为QTREE就是LCT,然后发现第一题是个树链剖分,于是以为QTREE就是树链剖分.写完后发现第二题是个树上倍增.

  综上,QTREE就是树上询问的一些题.

  来源:http://172.20.6.3/Categories.asp?page=11&order=ASC&channel=ID&c=8

  

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<bitset>
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc(){
  return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:* fs++;
}
inline int read(){
    int This=0,F=1; char ch=getc();
    while(ch<'0'||ch>'9'){
        if(ch=='-') F=-1;
        ch=getc();
    }
    while(ch>='0'&&ch<='9'){
        This=(This<<1)+(This<<3)+ch-'0';
        ch=getc();
    }
    return This*F;
}

inline void write(int x){
    if(x==0){
        putchar('0');
        return;
    }
    if(x<0){
        putchar('-');
        x=-x;
    }
    int num=0;char ch[16];
    while(x) ch[++num]=x%10+'0',x/=10;
    while(num) putchar(ch[num--]);
}

int siz[10010],top[10010],son[10010],fa[10010],dfn[10010],tot,head[10010],d[10010],fav[10010];
int n,maxx[40010];
struct edge
{
    int x,y,next,v;
}e[30000],o[10010];
inline void add(int x,int y,int v)
{
    tot++;
    e[tot]=(edge){x,y,head[x],v};
    head[x]=tot;
}
inline void change(int now,int l,int r,int x,int v)
{
    if(l==r)
    {    
        maxx[now]=v;
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid)
        change(now<<1,l,mid,x,v);
    else 
        change(now<<1|1,mid+1,r,x,v);
    maxx[now]=max(maxx[now<<1],maxx[now<<1|1]);
}
inline void dfs1(int x)
{
    siz[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].y==fa[x])
            continue;
        d[e[i].y]=d[x]+1;
        fa[e[i].y]=x;
        dfs1(e[i].y);
        siz[x]+=siz[e[i].y];
        if(siz[e[i].y]>siz[son[x]])
            son[x]=e[i].y;
    }
}
inline void dfs2(int x)
{
    tot++;
    dfn[x]=tot;
    if(!son[x])
        return ;
    top[son[x]]=top[x];
    dfs2(son[x]);
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].y==fa[x])
            continue;
        else if(e[i].y==son[x])
            change(1,1,n,dfn[son[x]],e[i].v);
        else 
        {
            top[e[i].y]=e[i].y;
            fav[e[i].y]=e[i].v;
            dfs2(e[i].y);
        }
    }
    
}
inline int ask(int now,int l,int r,int tl,int tr)
{
    if(tl<=l&&r<=tr)
        return maxx[now];
    int mid=l+r>>1,ans=0;
    if(tl<=mid)
        ans=max(ans,ask(now<<1,l,mid,tl,tr));
    if(tr>mid)
        ans=max(ans,ask(now<<1|1,mid+1,r,tl,tr));
    return ans;
}
inline int query(int x,int y)
{
    if(x==y)
        return 0;
    int fx=top[x],fy=top[y],ans=0;
    while(fx!=fy)
    {
        if(d[fx]>=d[fy])
        {
            ans=max(ans,ask(1,1,n,dfn[fx]+1,dfn[x]));
            ans=max(ans,fav[fx]);
            x=fa[fx];
            fx=top[x];
        }
        else 
        {
            ans=max(ans,ask(1,1,n,dfn[fy]+1,dfn[y]));
            ans=max(ans,fav[fy]);
            y=fa[fy];
            fy=top[y];
        }
    }
    if(x!=y)
    {
        if(d[x]<d[y])
            ans=max(ans,ask(1,1,n,dfn[x]+1,dfn[y]));
        else 
            ans=max(ans,ask(1,1,n,dfn[y]+1,dfn[x]));
    }
    return ans;
    
}
inline void gai(int nod,int v)
{
    int x=o[nod].x,y=o[nod].y;
    if(d[x]>d[y])
        swap(x,y);
    if(son[x]==y)
        change(1,1,n,dfn[y],v);
    else 
        fav[y]=v;
}
inline void check(int now,int l,int r)
{
    cout<<l<<' '<<r<<' '<<maxx[now]<<endl;
    if(l==r)
        return ;
    int mid=l+r>>1;
    check(now<<1,l,mid);
    check(now<<1|1,mid+1,r);
}
int main()
{
    //freopen("123.in","r",stdin);
    //freopen("123.out","w",stdout);
    int __size__ = 20 << 20; // 20MB
    char *__p__ = (char*)malloc(__size__) + __size__;
    __asm__("movl %0, %%esp
" :: "r"(__p__));
    for(int T=read();T;T--)
    {
        n=read();
        memset(head,0,sizeof(head));
        memset(siz,0,sizeof(siz));
        memset(top,0,sizeof(top));
        memset(son,0,sizeof(son));
        memset(fa,0,sizeof(fa));
        memset(dfn,0,sizeof(dfn));
        memset(d,0,sizeof(d));
        memset(fav,0,sizeof(fav));
        memset(maxx,0,sizeof(maxx));
        tot=0;
        for(int i=1;i<n;i++)
        {
            o[i].x=read();o[i].y=read();int w=read();
            add(o[i].x,o[i].y,w);
            add(o[i].y,o[i].x,w);
        }
        tot=0;
        dfs1(1);
        top[1]=1;
        dfs2(1);
        while(1)
        {
            char ch=getc();
            while(ch!='Q'&&ch!='C'&&ch!='D')
                ch=getc();
            if(ch=='Q')
            {
                int tx=read();int ty=read();
                cout<<query(tx,ty)<<endl;
            }
            else if(ch=='C')
            {
                int tot=read();int tv=read();
                gai(tot,tv);
            }
            else 
                break;
        }
    }/*
    for(int i=1;i<=n;i++)
    {
        cout<<i<<' '<<fav[i]<<endl;
    }*/
    //check(1,1,n);
}
p2047
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<bitset>
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc(){
  return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:* fs++;
}
inline int read(){
    int This=0,F=1; char ch=getc();
    while(ch<'0'||ch>'9'){
        if(ch=='-') F=-1;
        ch=getc();
    }
    while(ch>='0'&&ch<='9'){
        This=(This<<1)+(This<<3)+ch-'0';
        ch=getc();
    }
    return This*F;
}

inline void write(int x){
    if(x==0){
        putchar('0');
        return;
    }
    if(x<0){
        putchar('-');
        x=-x;
    }
    int num=0;char ch[16];
    while(x) ch[++num]=x%10+'0',x/=10;
    while(num) putchar(ch[num--]);
}
int n,d[10010],fa[10010][20],c[10010][20],head[10010],tot;
struct edge
{
    int y,next,v;
}e[20010];
inline void add(int x,int y,int v)
{
    tot++;
    e[tot]=(edge){y,head[x],v};
    head[x]=tot;
}
inline int get_sum(int x,int y)
{
    int sum=0;
    if(d[x]>d[y])
        swap(x,y);
    for(int t=15;t>=0;t--)
    {
        if(d[fa[y][t]]>=d[x])
            sum+=c[y][t],y=fa[y][t];
    }
    if(x==y)
        return sum;
    for(int t=15;t>=0;t--)
    {
        if(fa[x][t]!=fa[y][t])
            sum+=c[x][t]+c[y][t],x=fa[x][t],y=fa[y][t];
    }
    return sum+c[x][0]+c[y][0];
}
inline int get_lca(int x,int y)
{
    if(d[x]>d[y])
        swap(x,y);
    for(int t=15;t>=0;t--)
    {
        if(d[fa[y][t]]>=d[x])
            y=fa[y][t];
    }
    if(x==y)
        return x;
    for(int t=15;t>=0;t--)
    {
        if(fa[x][t]!=fa[y][t])
            x=fa[x][t],y=fa[y][t];
    }
    return fa[x][0];
}

inline int get_by_k(int x,int k)
{
    for(int t=15;t>=0;t--)
    {
        if((1<<t)<=k)
            x=fa[x][t],k-=(1<<t);
    }
    return x;
}
stack<int>q;
int main()
{
    //freopen("123.in","r",stdin);
    //freopen("123.out","w",stdout);
    for(int T=read();T;T--)
    {
        memset(d,0,sizeof(d));
        memset(head,0,sizeof(head));
        tot=0;
        //fa,c
        n=read();
        for(int i=1;i<n;i++)
        {
            int tx=read(),ty=read(),tv=read();
            add(tx,ty,tv);
            add(ty,tx,tv);
        }
        q.push(1);d[1]=1;
        while(q.size())
        {
            int x=q.top();q.pop();
            for(int i=head[x];i;i=e[i].next)
            {
                if(d[e[i].y])
                    continue;
                d[e[i].y]=d[x]+1;
                fa[e[i].y][0]=x;
                c[e[i].y][0]=e[i].v;
                q.push(e[i].y);
            }
        }
        for(int t=1;t<=15;t++)
        {
            for(int i=1;i<=n;i++)
            {
                fa[i][t]=fa[fa[i][t-1]][t-1];
                c[i][t]=c[i][t-1]+c[fa[i][t-1]][t-1];
            }
        }
        while(1)
        {
            char ch=getc();
            while(ch!='D'&&ch!='K')
                ch=getc();
            if(ch=='D')
            {
                ch=getc();
                if(ch=='I')
                    cout<<get_sum(read(),read())<<endl;
                else 
                    break;
            }
            else 
            {
                int x=read();int y=read();int k=read();
                int lca=get_lca(x,y);
                if(d[x]-d[lca]+1>=k)
                    cout<<get_by_k(x,k-1);
                else 
                    cout<<get_by_k(y,d[y]+d[x]-d[lca]-k+1-d[lca]);
                cout<<endl;
            }
        }
    }
}
p2048
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<bitset>
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc(){
  return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:* fs++;
}
inline int read(){
    int This=0,F=1; char ch=getc();
    while(ch<'0'||ch>'9'){
        if(ch=='-') F=-1;
        ch=getc();
    }
    while(ch>='0'&&ch<='9'){
        This=(This<<1)+(This<<3)+ch-'0';
        ch=getc();
    }
    return This*F;
}

inline void write(int x){
    if(x==0){
        putchar('0');
        return;
    }
    if(x<0){
        putchar('-');
        x=-x;
    }
    int num=0;char ch[16];
    while(x) ch[++num]=x%10+'0',x/=10;
    while(num) putchar(ch[num--]);
}
int n,head[100010],tot,dfn[100010],top[100010],fa[100010],siz[100010],son[100010],a[400010],num[100010];
struct edge
{
    int y,next;
}e[200010];
void add(int x,int y)
{
    tot++;
    e[tot]=(edge){y,head[x]};
    head[x]=tot;
}
void dfs1(int x)
{
    siz[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].y==fa[x])
            continue;
        //d[e[i].y]=d[x]+1;
        fa[e[i].y]=x;
        dfs1(e[i].y);
        siz[x]+=siz[e[i].y];
        if(siz[e[i].y]>siz[son[x]])
            son[x]=e[i].y;
    }
}
void dfs2(int x)
{
    tot++;
    dfn[x]=tot;
    num[tot]=x;
    if(!son[x])
        return ;
    top[son[x]]=top[x];
    dfs2(son[x]);
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].y==fa[x]||e[i].y==son[x])continue;
        top[e[i].y]=e[i].y;
        dfs2(e[i].y);
    }
}
int ask(int now,int l,int r,int tl,int tr)
{
    if(tl<=l&&r<=tr)
        return a[now];
    int mid=l+r>>1,t=0;
    if(tl<=mid)
    {
        t=ask(now<<1,l,mid,tl,tr);
        if(t)
            return t;
    }
    if(tr>mid)
        return ask(now<<1|1,mid+1,r,tl,tr);
    else 
        return 0;
}
int query(int x)
{
    int fx=top[x],ans=0,t=0;
    while(fx!=1)
    {
        t=ask(1,1,n,dfn[fx],dfn[x]);
        if(t)//一旦有,那就是
            ans=t;
        x=fa[fx];
        fx=top[x];
    }
    t=ask(1,1,n,dfn[1],dfn[x]);
    if(t)
        return t;
    else 
        return ans;
}
void change(int now,int l,int r,int x)
{
    if(l==r)
    {
        a[now]=x-a[now];

        return ;
    }
    int mid=l+r>>1;
    if(x<=mid)
        change(now<<1,l,mid,x);
    else 
        change(now<<1|1,mid+1,r,x);
    a[now]=a[now<<1]?a[now<<1]:a[now<<1|1];
}/*
void check(int now,int l,int r)
{
    cout<<l<<' '<<r<<' '<<a[now]<<endl;
    if(l==r)
        return ;
    int mid=l+r>>1;
    check(now<<1,l,mid);
    check(now<<1|1,mid+1,r);
}*/

int main()
{
    //freopen("123.in","r",stdin);
    n=read();int Q=read();
    for(int i=1;i<n;i++)
    {
        int tx=read();int ty=read();
        add(tx,ty);
        add(ty,tx);
    }
    num[0]=-1;
    tot=0;
    dfs1(1);
    top[1]=1;
    dfs2(1);
    for(;Q;Q--)
    {
        if(read())
        {
            write(num[query(read())]);
            putchar(10);
        }
        else 
        {
            change(1,1,n,dfn[read()]);
        }
    }
}
p2049

  p2047

  简单的树链剖分.

  两遍dfs剖一下.用线段树维护树链上最粗的枝干,每个树链的top再记录自己到父亲的那条边.每次修改就单点修改,查询就边跳边取max.

  应该用不着记录"每个树链的top到父亲的那条边",这样看起来很不简洁,应该是我写的太糙了.


  p2048

  既然没有修改操作,为什么不用树上倍增水过呢?
  记录每个点的2^k的祖先和到达那个祖先的路径长度.

  查询操作大体上和求lca很相似了.两点路径长就边跳边+=,求x到y的路径上第k个结点有一点点麻烦.先求出lca,这样就可以通过d[]数组得到lca和x之间有几个点.如果在lca和x的路径上就从x往上跳k-1次,否则从y往上跳d[y]+d[x]-2*d[lca]-k+1次.


  p2049

  继续树链剖分.

  dfn[i]表示编号为i的花的dfs序,num[i]表示dfs序为i的花的编号.

  用线段树维护链上第一个出现红花的时间戳(dfn),显然只需要贪心一下.

  操作一可以单点修改,操作二边取min边往上跳.最后在num里找到编号即可.

原文地址:https://www.cnblogs.com/qywyt/p/10537405.html