jzoj5844. c

版权声明:233 https://blog.csdn.net/gmh77/article/details/82011184

题目描述

Description
给定一个无向连通图,n 个点(下标从 1 开始),m 条边,每条边有一个颜色。保证无自环,没有长度超过 2 的简单环。
现有 q 个询问:给出两个点 x、y,选择一条 x 到 y 简单路径(不经过重复的点),经过的边将形成一个颜色序列,价值为相同颜色的极大连续段个数,求出最大的价值。

Input
第一行,一个正整数n,一个自然数 m。
接下来m 行,每行三个正整数 u,v,w,代表一条边(u,v),颜色为 w。接下来一行,一个自然数 q。
接下来q 行,每行两个正整数 x,y,代表一次询问。

Output
共 q 行,每行一个自然数,代表该询问的答案。
这里写图片描述

(CSDN可以拖拽图片上传真是舒服)

task1

题目说是”没有长度超过 2 的简单环”,实际就是一颗有重边的树
(真特么坑)

以为数据很小,所以直接暴力乱搞就行了

task2

树剖?

task3

圆方树?
反正都没写

task4

水法?

task5

因为p=0,所以

int main(){}

就有1分了2333

task6~8

不会

task9

部分分真多

因为一条边可能有很多种颜色,不好处理,但实际上只需要保留任意三种不同的颜色就行了
(当然如果不够三种颜色就全部保留)

证明其合法性,只要证明这样做可以构出最优解
因为题目要找的是一条简单路径,所以如果一条边两端的边颜色与自己的其中两种颜色相同,那么第三种颜色肯定与前后两种不同


因为题目求的是x–>y的路径,所以考虑计算x–>lca和y–>lca,最后将两条路径合并
然后就可以用倍增维护

设f[i][j][0~2][0~2]表示
从点i到i的2^j级父亲的路径,首尾的颜色编号为0~2/0~2的最大答案
为了方便求具体颜色,设fa[i][j]和fa2[i][j]表示i的第2^j级和第(2^j)-1级父亲

求完f后,问题是怎么具体求x–>lca和y–>lca
可以分别维护一个数组,表示从x到当前位置,且结尾颜色为0~2的最大答案
这样每次把相邻的两个f合并更新答案,最后把x和y合并

code

不难想,就是细节很多
调了一个晚上最后发现l写成了k

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
using namespace std;

int a[600001][3];
int b[300001][3];
int ls[300001];
bool bz[300001];
int fa[300001][17];
int fa2[300001][17];
int f[300001][17][3][3];
int dp[300001];
int c[2][3];
int C[3];
int d[2][3];
int x[2];
int Q,n,m,i,j,k,l,len,X,Y,Z,ans,L;

void swap(int &a,int &b) {int c=a;a=b;b=c;}

void New(int x,int y,int z)
{
    len++;
    a[len][0]=y;
    a[len][1]=z;
    a[len][2]=ls[x];
    ls[x]=len;
}

void dfs(int Fa,int t)
{
    int I,i,j,k,l,T;

    fa[t][0]=Fa;
    fa2[t][0]=t;

    fo(i,1,16)
    {
        fa[t][i]=fa[fa[t][i-1]][i-1];
        fa2[t][i]=fa[fa2[t][i-1]][i-1];
    }

    if (b[t][0]) f[t][0][0][0]=1;
    if (b[t][1]) f[t][0][1][1]=1;
    if (b[t][2]) f[t][0][2][2]=1;

    fo(I,1,16)
    if (fa[t][I])
    {
        T=fa[t][I-1];

        fo(i,0,2)
        {
            fo(j,0,2)
            if (f[t][I-1][i][j])
            {
                fo(k,0,2)
                {
                    fo(l,0,2)
                    if (f[T][I-1][k][l])
                    f[t][I][i][l]=max(f[t][I][i][l],f[t][I-1][i][j]-(b[fa2[t][I-1]][j]==b[T][k])+f[T][I-1][k][l]);
                }
            }
        }
    }
    else
    break;

    for (i=ls[t]; i; i=a[i][2])
    if (a[i][0]!=Fa)
    {
        if (!b[a[i][0]][0])
        b[a[i][0]][0]=a[i][1];
        else
        if (!b[a[i][0]][1] && b[a[i][0]][0]!=a[i][1])
        b[a[i][0]][1]=a[i][1];
        else
        if (!b[a[i][0]][2] && b[a[i][0]][0]!=a[i][1] && b[a[i][0]][1]!=a[i][1])
        b[a[i][0]][2]=a[i][1];
    }

    bz[t]=1;
    for (i=ls[t]; i; i=a[i][2])
    if (a[i][0]!=Fa)
    {
        if (!bz[a[i][0]])
        {
            dp[a[i][0]]=dp[t]+1;
            dfs(t,a[i][0]);
        }
    }
}

void jump(int t,int i)
{
    int j,k,l;

    memset(C,0,sizeof(C));
    fo(j,0,2)
    if (d[t][j])
    {
        fo(k,0,2)
        if (b[x[t]][k])
        {
            fo(l,0,2)
            if (f[x[t]][i][k][l])
            C[l]=max(C[l],c[t][j]-(d[t][j]==b[x[t]][k])+f[x[t]][i][k][l]);
        }
    }

    fo(j,0,2)
    {
        c[t][j]=C[j];
        d[t][j]=b[fa2[x[t]][i]][j];
    }
    x[t]=fa[x[t]][i];
}

int lca(int x,int y)
{
    int i;

    fd(i,16,0)
    if (dp[fa[x][i]]>=dp[y])
    x=fa[x][i];

    fd(i,16,0)
    if (fa[x][i]!=fa[y][i])
    {
        x=fa[x][i];
        y=fa[y][i];
    }

    if (x!=y) x=fa[x][0];
    return x;
}

int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);

    scanf("%d%d",&n,&m);
    fo(i,1,m)
    {
        scanf("%d%d%d",&X,&Y,&Z);

        New(X,Y,Z);
        New(Y,X,Z);
    }

    dp[1]=1;
    dfs(0,1);

    for (scanf("%d",&Q); Q; Q--)
    {
        scanf("%d%d",&x[0],&x[1]);

        if (x[0]==x[1])
        {
            printf("0\n");
            continue;
        }

        if (dp[x[0]]<dp[x[1]])
        swap(x[0],x[1]);

        L=lca(x[0],x[1]);

        memset(c,0,sizeof(c));
        memset(d,0,sizeof(d));
        fo(i,0,2)
        {
            d[0][i]=b[x[0]][i];
            if (x[1]!=L)
            d[1][i]=b[x[1]][i];
        }
        x[0]=fa[x[0]][0];

        fo(i,0,2)
        if (d[0][i])
        c[0][i]=1;

        if (x[1]!=L)
        {
            fo(i,0,2)
            if (d[1][i])
            c[1][i]=1;
            x[1]=fa[x[1]][0];
        }
        else
        {
            fd(i,16,0)
            if (dp[fa[x[0]][i]]>=dp[x[1]])
            jump(0,i);

            printf("%d\n",max(max(c[0][0],c[0][1]),c[0][2]));
            continue;
        }

        fd(i,16,0)
        if (dp[fa[x[0]][i]]>=dp[x[1]])
        jump(0,i);

        fd(i,16,0)
        if (fa[x[0]][i]!=fa[x[1]][i])
        jump(0,i),jump(1,i);

        if (x[0]!=x[1])
        jump(0,0),jump(1,0);

        ans=0;
        fo(i,0,2)
        if (d[0][i])
        {
            fo(j,0,2)
            if (d[1][j])
            ans=max(ans,c[0][i]-(d[0][i]==d[1][j])+c[1][j]);
        }
        printf("%d\n",ans);
    }

    fclose(stdin);
    fclose(stdout);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/gmh77/article/details/82011184
今日推荐