樹鏈剖分

http://blog.sina.com.cn/s/blog_7a1746820100wp67.html 別人轉的講解, 看的這個學的。

感覺不是必要的方法, 其他方法也能做的, 一般要維護樹種路徑的最值時才需要這個算法

spoj375

對邊權的路徑剖分

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>

using namespace std;
const int maxn=10000+123;
int T[maxn<<2];
int M;
void initT(int x)
{
    memset (T, 0, sizeof(T));
    M=1<<((int)ceil(log(x+1.0)/log(2.0)));
}
void update(int x, int v)
{
    for (T[x+=M]=v, x>>=1; x; x>>=1)
    {
        T[x]=max(T[x<<1], T[x<<1|1]);
    }
}

int query(int l, int r)
{
    int res=-1;
    for (l+=M-1, r+=M+1; l^r^1; l>>=1, r>>=1)
    {
        if(~l&1)res=max(T[l^1], res);
        if( r&1)res=max(T[r^1], res);
    }
    return res;
}

struct Edge {
    int v, next, w;
}edge[maxn<<1];
int head[maxn], cnt;
void addedge(int u, int v, int w)
{
    edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u];
    head[u]=cnt++;
}

int dep[maxn], pos[maxn], fa[maxn], top[maxn], son[maxn], siz[maxn];
int idx;
/// pos the position of father edge int seg-tree
void dfs(int u)
{
    siz[u]=1; son[u]=-1;
    for (int p=head[u]; ~p; p=edge[p].next)
    {
        const int &v=edge[p].v;
        if(v==fa[u])continue;
        fa[v]=u;
        dep[v]=dep[u]+1;
        dfs(v);
        if(siz[v]>siz[son[u]])son[u]=v;
        siz[u]+=siz[v];
    }
}

void dfs_(int u, int tp)
{
    pos[u]=++idx; top[u]=tp;
    if(~son[u])dfs_(son[u], top[u]);///非葉節點遍歷重兒子
    for (int p=head[u]; ~p; p=edge[p].next)
    {
        if(edge[p].v!=son[u] && edge[p].v!=fa[u])
            dfs_(edge[p].v, edge[p].v);///輕邊
    }
}

int find(int u, int v)
{
    int fu=top[u], fv=top[v], tmp=-1;
    while (fu!=fv)
    {
       if(dep[fu]<dep[fv])
       {
			swap(fu, fv); swap(u, v);
       }
       tmp=max(tmp, query(pos[fu], pos[u]));
       u=fa[fu]; fu=top[u];
    }
    if(u==v)return tmp;
    if(dep[u]>dep[v])swap(u, v);///u v不同,但在同一重鏈上
    return max(tmp, query(pos[son[u]], pos[v]));
}

void init()
{
    memset (head, -1, sizeof(head));
    cnt=0;
}

int main()
{
    int cas; scanf("%d", &cas);
    while (cas--)
    {
        int n; scanf("%d", &n); 
        init();
        idx=dep[1]=0;
        fa[1]=-1;
        
        for (int i=1; i<n; ++i)
        {
            int a, b, c; scanf("%d%d%d", &a, &b, &c);
            addedge(a, b, c);
            addedge(b, a, c);
        }
        dfs(1);
        dfs_(1, 1);
		initT(idx);
		///printf("idx===%d %d\n", idx, M);
        for (int u=1; u<=n; ++u)
        {
            for (int p=head[u]; ~p; p=edge[p].next)
            {
                const int v=edge[p].v;
                if(dep[v]>dep[u])
                    update(pos[v], edge[p].w);
            }
        }
       
        char op[20];
        for (scanf("%s", &op); op[0]!='D'; scanf("%s", &op))
        {
            int a, b; scanf("%d%d", &a, &b);
            if(op[0]=='Q')printf("%d\n", find(a, b));
            else
            {
                a--;
                int v1=edge[a<<1].v, v2=edge[a<<1|1].v;
                if(dep[v1]<dep[v2])v1=v2;
                update(pos[v1], b);
            }
        }
    }
    return 0;
}
/*
2
3
1 2 100
2 3 200
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
4
1 2 1
2 4 2
3 4 3
QUERY 1 3
Q 1 2
CHANGE 1 3
QUERY 3 4
C 1 3
Q 1 2
DONE

*/

bupt 649  Gao on a Tree II

對點權的路徑剖分

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>

using namespace std;
const int maxn=200000+123;
//int T[maxn<<2];
///map<int, int>mp[maxn<<2];
multimap<int, int>mm;
struct Edge {
    int v, next, w;
}edge[maxn<<1];
int head[maxn], cnt;
void addedge(int u, int v, int w=0)
{
    edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u];
    head[u]=cnt++;
}

int dep[maxn], pos[maxn], fa[maxn], top[maxn], son[maxn], siz[maxn];
int idx;
/// pos the position of father edge int seg-tree
///樹鏈剖分就是將樹拆成鏈,
void dfs(int u)
{
    siz[u]=1; son[u]=-1;
    for (int p=head[u]; ~p; p=edge[p].next)
    {
        const int &v=edge[p].v;
        if(v==fa[u])continue;
        fa[v]=u;
        dep[v]=dep[u]+1;
        dfs(v);
        if(siz[v]>siz[son[u]])son[u]=v;
        siz[u]+=siz[v];
    }
}

void dfs_(int u, int tp)
{
    pos[u]=++idx; top[u]=tp;
    if(~son[u])dfs_(son[u], top[u]);///非葉節點遍歷重兒子
    for (int p=head[u]; ~p; p=edge[p].next)
    {
        if(edge[p].v!=son[u] && edge[p].v!=fa[u])
            dfs_(edge[p].v, edge[p].v);///輕邊
    }
}

bool find(int u, int v, int x)
{
    int fu=top[u], fv=top[v];
    multimap<int, int>::iterator itu=mm.upper_bound(x), it;
    multimap<int, int>::iterator itl=mm.lower_bound(x);
    int l, r;
    if(itl==mm.end() || itl->first!=x) return false;
    while (fu!=fv)
    {
		if(dep[fu]<dep[fv])
		{
			swap(fu, fv); swap(u, v);
		}
       ///tmp=max(tmp, query(pos[fu], pos[u]));
       //if(query(pos[fu], pos[u]))return true;
       ///if(pos[fu]<=l && pos[u])
		///printf("%d %d\n", pos[fu], pos[u]);
		for (it=itl; it!=itu; ++it)
			if(pos[fu]<=it->second && pos[u]>=it->second)return true;
		u=fa[fu]; fu=top[u];
		///printf("f%d f%d\n", fu, fv);
    }
    if(u==v)
    {
    	for (it=itl; it!=itu; ++it)
			if(pos[u]==it->second)return true;
    }
    if(dep[u]>dep[v])swap(u, v);///u v不同,但在同一重鏈上
    ///return max(tmp, query(pos[son[u]], pos[v]));
    ///printf("p %d p %d\n", pos[u], pos[v]);
    for (it=itl; it!=itu; ++it)
		if(pos[u]<=it->second && pos[v]>=it->second)return true;
    return false;
}

void init()
{
    memset (head, -1, sizeof(head));
    cnt=0;
}
void initr(int rt)
{
	idx=0; dep[rt]=0;
	fa[rt]=0;
}
int w[maxn];

int main()
{
	int cas; scanf("%d", &cas);
	while (cas--)
	{
		int n, m; scanf("%d%d", &n, &m);
		init();
		initr(1);
		for (int i=1; i<=n; ++i)
		{
			scanf("%d", w+i);
		}
		for (int i=1; i<n; ++i)
		{
			int a, b; scanf("%d%d", &a, &b);
			addedge(a, b); addedge(b, a);
		}
		dfs(1);
		dfs_(1, 1);
		///initT(idx);
		mm.clear();
		for (int i=1; i<=n; ++i)
			///update(pos[i], w[i]);
			mm.insert(make_pair(w[i], pos[i]));
		///for (int i=0; i<=n; ++i)printf("%d %d\n", i, pos[i]);
		for (int i=0; i<m; ++i)
		{
			char op[5]; scanf("%s", op);
			if(op[0]=='Q')
			{
				int a, b, c; scanf("%d%d%d", &a, &b, &c);
				if(find(a, b, c))puts("Find");
				else puts("NotFind");
			}
			else 
			{
				int a, b; scanf("%d%d", &a, &b);
				multimap<int, int>::iterator itu=mm.upper_bound(w[a]), it;
				multimap<int, int>::iterator itl=mm.lower_bound(w[a]);
				for (it=itl; it!=itu; ++it)
				{
					if(it->second==pos[a])
					{
						mm.erase(it);
						break;
					}
				}
				mm.insert(make_pair(b, pos[a]));
				w[a]=b;
			}
		}
		puts("");
	}
}
/*


*/




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章