bzoj 2959: 长跑

bzoj 2959: 长跑

可以看作是这道题的加强版:https://www.luogu.org/problemnew/show/P2542

看到动态维护\(Tarjan\)缩点就考虑使用\(LCT\),使用一个并查集\(f\)表示点\(i\)所在的点双的“标志”点是哪一个,\(link\)时分类讨论一下即可

然后这题卡常,我们无法使用\(findroot\),于是考虑再用一个并查集表示两点之间的连通性即可

剩下的就和那个弱化版差不多了

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define eps 1e-8
int n,m,fa[150050],con[150050],f[150050],tag[150050],ch[150050][2];
int val[150050],sum[150050],w[150050];

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

int find(int x)
{
    if (f[x]==x) return x;
    f[x]=find(f[x]);
    return f[x];
}

int findcon(int x)
{
    if (con[x]==x) return x;
    con[x]=findcon(con[x]);
    return con[x];
}

bool isroot(int x)
{
    int fx=find(fa[x]);
    return ((ch[fx][0]!=x) && (ch[fx][1]!=x));
}

void pushup(int x) {sum[x]=w[x]+sum[ch[x][0]]+sum[ch[x][1]];}
void puttag(int x) {swap(ch[x][0],ch[x][1]);tag[x]^=1;}
void pushdown(int x)
{
    if (tag[x])
    {
        if (ch[x][0]) puttag(ch[x][0]);
        if (ch[x][1]) puttag(ch[x][1]);
        tag[x]=0;
    }
}

void update(int x)
{
    //if (x==1) cout << "NOW " << ch[x][0] << " " << ch[x][1] << endl;
    if (!isroot(x)) update(find(fa[x]));pushdown(x);
}

void rotate(int x)
{
    int y=find(fa[x]),z=find(fa[y]),k=(ch[y][1]==x),w=ch[x][k^1];
    if (!isroot(y)) ch[z][ch[z][1]==y]=x;
    ch[x][k^1]=y;ch[y][k]=w;
    if (w) fa[w]=y;fa[y]=x;fa[x]=z;
    pushup(y);pushup(x);
}

void splay(int x)
{
    update(x);
    while (!isroot(x))
    {
        int y=find(fa[x]),z=find(fa[y]);
        if (!isroot(y))
        {
            if ((ch[z][1]==y)^(ch[y][1]==x)) rotate(x);else rotate(y);
        }
        rotate(x);
    }
    pushup(x);
}

void access(int x)
{
    int y=0;
    while (x)
    {
        splay(x);ch[x][1]=y;pushup(x);
        y=x;fa[y]=find(fa[y]);x=find(fa[x]);
    }
}

int findroot(int x)
{
    access(x);splay(x);
    while (ch[x][0])
    {
        pushdown(x);x=ch[x][0];
    }
    splay(x);return x;
}

void out()
{
    cout <<endl;
    rep(i,1,n) cout << ch[i][0] << " " << ch[i][1] <<" ";cout << endl;
    cout << endl;
}

void makeroot(int x) {access(x);splay(x);puttag(x);}
void link(int x,int y) {makeroot(x);fa[x]=y;}
void split(int x,int y) {makeroot(x);access(y);splay(y);}
void cut(int x,int y) {split(x,y);ch[y][0]=0;fa[x]=0;pushup(y);}
void del(int x,int y)
{
    f[x]=y;pushdown(x);
    if (ch[x][0]) del(ch[x][0],y);
    if (ch[x][1]) del(ch[x][1],y);
}

int main()
{
    n=read();m=read();
    rep(i,1,n)
    {
        val[i]=read();sum[i]=val[i];w[i]=val[i];
        f[i]=i;con[i]=i;
    }
    rep(i,1,m)
    {
        int op=read(),x=read(),y=read();
        if (op==1)
        {
            int fx=find(x),fy=find(y);
            if (fx==fy) continue;
            int cx=findcon(fx),cy=findcon(fy);
            if (cx!=cy)
            {
                link(fx,fy);
                con[cx]=cy;
            }
            else
            {
                split(fx,fy);w[fy]=sum[fy];
                del(fy,fy);ch[fy][0]=0;pushup(fy);
            }
        }
        else if (op==2)
        {
            int fx=find(x);splay(fx);
            w[fx]+=(y-val[x]);sum[fx]+=(y-val[x]);
            val[x]=y;pushup(fx);
        }
        else if (op==3)
        {
            int fx=find(x),fy=find(y);
            int cx=findcon(fx),cy=findcon(fy);
            if (cx!=cy) puts("-1");
            else
            {
                split(fx,fy);
                printf("%d\n",sum[fy]);

            }
        }
    }
    return 0;
}
/*
9 31
10 20 30 40 50 60 70 80 90
3 1 2
1 1 3
1 1 2
1 8 9
1 2 4
1 2 5
1 4 6
1 4 7
3 1 8
3 8 8
1 8 9
3 8 8
3 7 5
3 7 3
1 4 1
3 7 5
3 7 3
1 5 7
3 6 5
3 3 6
1 2 4
1 5 5
3 3 6
2 8 180
3 8 8
2 9 190
3 9 9
2 5 150
3 3 6
2 1 210
3 3 6
 */

原文地址:https://www.cnblogs.com/encodetalker/p/11123906.html

时间: 2024-10-15 02:29:50

bzoj 2959: 长跑的相关文章

bzoj 2959 长跑(LCT+BCC+并查集)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2959 [题意] n个点,提供操作:连边,修改点权,查询自定义边的方向后起点a终点b能经过的最大点权和. [思路] 对于一个边的双连通分量,显然可以将权值全部获得. 如果没有连边操作,我们只需要将一个bcc缩点后求得a->b路径上的点权和即可. 加上连边后,使用并查集代表一个bcc,如果u,v之间不连通直接连边,如果已经连通则构成一个bcc,使用并查集将LCT的所有节点合并. 注意缩点

【刷题】BZOJ 2959 长跑

Description 某校开展了同学们喜闻乐见的阳光长跑活动.为了能"为祖国健康工作五十年",同学们纷纷离开寝室,离开教室,离开实验室,到操场参加3000米长跑运动.一时间操场上熙熙攘攘,摩肩接踵,盛况空前. 为了让同学们更好地监督自己,学校推行了刷卡机制. 学校中有n个地点,用1到n的整数表示,每个地点设有若干个刷卡机. 有以下三类事件: 修建了一条连接A地点和B地点的跑道. A点的刷卡机台数变为了B. 进行了一次长跑.问一个同学从A出发,最后到达B最多可以刷卡多少次. 具体的要求

BZOJ 2959 长跑 Link-Cut-Tree+并查集

题目大意:给定n个点,支持以下操作: 1.在某两个点之间连接一条无向边 2.改变某个点的权值 3.将每条边设定一个方向,然后从x走到y,求能经过的所有点的权值和 首先如果这个图是静态的,我们把边双都缩点,那么每次询问显然就是两个点所在边双路径上的点权和 现在图是动态的,因此我们用动态树维护一下就行了 如果连边的两个点不连通,就在LCT中连接这两个点 如果连边的两个点已经连通,就将这个两个点路径上的所有点用并查集缩点 时间复杂度O(mlogn) 似乎用链剖会快一些? #include <cstdi

2959: 长跑|LCT+并查集

慎入-此人代码自带5倍常数.. 静态的话就是随便搞出一棵生成树来,然后把环缩起来,询问的答案就是路径上的权值和 动态的就需要LCT来维护生成树,每遇到连起边来就形成环的情况时,就把这个环缩成一个点 动态的查询一条链上的权值和. 为什么我的代码的常数这么大--.后几个点在本地跑5s #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cst

【BZOJ】【2765】【JLOI2010】铁人双项比赛

计算几何/半平面交 本来我是想去写POJ 1755的,然后想起了这道跟它很像的题,但应该是弱化版,所以就先写了这个…… 我们可以发现每个人的总用时,与k是呈一次函数关系的:$time_i=\frac{k}{Vrun_i}+\frac{S-k}{Vride_i}$ 然而我们要找的是某个k,使得$min(time_n-time_i)$最大 那么就是一个线性规划问题了……这个也可以用半平面交来做……(蒟蒻并不会单纯形) 下面的部分为了偷懒简洁我就用$a_i$和$b_i$来代替两种速度…… 我一开始想的

BZOJ 1013: [JSOI2008]球形空间产生器sphere

二次联通门 : BZOJ 1013: [JSOI2008]球形空间产生器sphere /* BZOJ 1013: [JSOI2008]球形空间产生器sphere 高斯消元 QAQ SB的我也能终于能秒题了啊 设球心的坐标为(x,y,z...) 那么就可以列n+1个方程,化化式子高斯消元即可 */ #include <cstdio> #include <iostream> #include <cstring> #define rg register #define Max

bzoj 3309 DZY Loves Math - 莫比乌斯反演 - 线性筛

对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b). Input 第一行一个数T,表示询问数. 接下来T行,每行两个数a,b,表示一个询问. Output 对于每一个询问,输出一行一个非负整数作为回答. Sample Input 4 7558588 9653114 6514903 445

【BZOJ】[HNOI2009]有趣的数列

[算法]Catalan数 [题解] 学了卡特兰数就会啦>_<! 因为奇偶各自递增,所以确定了奇偶各自的数字后排列唯一. 那么就是给2n个数分奇偶了,是不是有点像入栈出栈序呢. 将做偶数标为-1,做奇数标为+1,显然当偶数多于奇数时不合法,因为它压不住后面的奇数. 然后其实这种题目,打表就可知啦--QAQ 然后问题就是求1/(n+1)*C(2n,n)%p了,p不一定是素数. 参考bzoj礼物的解法. 看到网上清一色的素数筛+分解质因数解法,不解了好久,感觉写了假的礼物-- 后来觉得礼物的做法才比

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3