poj3237 暴力在线LCA

     给一棵带权树,三种操作,查询x到y的的路径上最大的边权;修改第x条边的权值为y;取反x到y的路径上所有的边权。每次查询,求出lca,从x,y爬到lca点取最大值,修改直接改权值就行,取反同查询...一定是这题的数据太弱了...这么暴力的做法都给过......

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;

const int POW = 18;
const int maxn=201000;
struct node
{
    int v,w,id;
    node()
    {

    }
    node(int x,int y,int z)
    {
        v=x; w=y; id=z;
    }
};
vector<node> edge[maxn];
int w[maxn];
int p[maxn][22];
int d[maxn];
int f[maxn];
int n,m,k;
node pre[maxn];
void dfs(int u,int fa){
    d[u]=d[fa]+1;
    p[u][0]=fa;
    for(int i=1;i<POW;i++) p[u][i]=p[p[u][i-1]][i-1];
    int sz=edge[u].size();
    for(int i=0;i<sz;i++){
        int v=edge[u][i].v;
        if(v==fa) continue;
        dfs(v,u);
        pre[v]=edge[u][i];
        f[v]=u;
    }
}
int lca( int a, int b ){
    if( d[a] > d[b] ) swap(a,b);
    if( d[a] < d[b] ){
        int del = d[b] - d[a];
        for( int i = 0; i < POW; i++ ) if(del&(1<<i)) b=p[b][i];
    }
    if( a != b ){
        for( int i = POW-1; i >= 0; i-- )
            if( p[a][i] != p[b][i] )
                 a = p[a][i] , b = p[b][i];
        a = p[a][0], b = p[b][0];
    }
    return a;
}
char cmd[10];
int main()
{
//    freopen("in.txt","r",stdin);
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        memset(d,0,sizeof d);
        memset(p,0,sizeof p);
        memset(pre,0,sizeof pre);
        memset(f,0,sizeof f);
        memset(w,0,sizeof w);
        scanf("%d",&n);
        int x,y,z;
        for (int i=1; i<=n; i++)
        {
            edge[i].clear();
        }
        for (int i=1; i<n; i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            edge[x].push_back(node(y,z,i));
            edge[y].push_back(node(x,z,i));
            w[i]=z;
        }
        dfs(1,-1);
        while(true)
        {
            scanf("%s",cmd);
            if (cmd[0]=='Q')
            {
                scanf("%d%d",&x,&y);
                int t=lca(x,y);
                int minn=(1<<30);
                minn=-minn;
                while (x!=t)
                {
                    minn=max(minn,w[pre[x].id]);
                    x=f[x];
                }
                while (y!=t)
                {
                    minn=max(minn,w[pre[y].id]);
                    y=f[y];
                }
                printf("%d\n",minn);
            }
            else
            if (cmd[0]=='C')
            {
                scanf("%d%d",&x,&y);
                w[x]=y;
            }
            else
            if (cmd[0]=='N')
            {
                scanf("%d%d",&x,&y);
                int t=lca(x,y);
                while (x!=t)
                {
                    w[pre[x].id]=-w[pre[x].id];
                    x=f[x];
                }
                while (y!=t)
                {
                    w[pre[y].id]=-w[pre[y].id];
                    y=f[y];
                }
            }
            else break;
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值