九校联考DAT2T3(启发式合并,倍增)

题目描述

南极的企鹅王国大学中生活着 n 只企鹅,作为 21 世纪的优秀大学生, 企鹅们积极响应“大众创业,万众创新”的号召,纷纷创业。但是创业需要资 金,企鹅们最近手头比较紧,只能互相借钱。

企鹅的借钱行为是有规律可循的:每只企鹅只会借一次钱,并且只会 从一只企鹅那里借钱。借钱关系中不存在环(即不存在类似“金企鹅欠银企 鹅钱,银企鹅欠铜企鹅钱,铜企鹅欠金企鹅钱”这种情况)。

企鹅的还钱行为也是有规律可循的:每只企鹅一旦新获得了一笔钱,就会立刻用这笔钱尽可能偿还自己欠的债务,直到债务偿清或用光这笔钱。它只会使用新获得的这笔钱,至于以前它有没有钱、有多少钱,与还钱行为无关。

企鹅们经常会做美梦。在一只企鹅 A 的梦里,它梦见自己创业成功,一下子获得了 + + ∞ 元钱,于是(按照上文的还钱规则)它赶快把钱用来还债, 接着拿到钱的那只企鹅也赶快把钱用来还债……如此往复,直到所有获得钱的企鹅都完成了还债操作。梦醒之后,它开心地把梦的内容告诉了另外一只企鹅 B,企鹅 B 听了,也很开心,于是它问道:在你的梦里,我获得了多少钱呢?(指 B 去还债之前手里的钱,包括后来用于还债的钱和还债后 B 手里剩下的钱。)

梦毕竟是梦,对实际的欠债情况没有影响。

输入格式

第一行两个整数 n 和 m,表示有 n 只企鹅,m 个操作。接下来 m 行,有两种可能的格式:

-0 a b c:修改操作,企鹅 a 向企鹅 b 借了 c 元钱。

-1 a b:查询操作, 询问假如 a 有了 + + ∞ 元钱,企鹅 b 会净收入多少钱。

本题强制在线,也就是说:对于每个操作输入的变量 a, b, c(如果没有c,那就只有 a, b)都不是实际的 a, b, c,想获得实际的 a, b, c 应当经过以下操作:

a = (a + lastans) % n + 1;

b = (b + lastans) % n + 1;

c = (c + lastans) % n + 1;

其中,lastans 是上一次询问的答案。如果没有上一次询问,lastans 为0。

输出格式

对每个询问操作,输出一行一个数表示答案。

样例数据

input

5 9
0 1 2 1
0 0 1 2
1 0 1   
1 2 4   
0 2 1 1
1 2 0   
0 3 1 0
1 4 2   
1 3 4   

output

3
2
0
1
0

数据规模与约定

数据分为以下几种:

第一种:占 10%,n≤5000 且 m≤10000;

第二种:占 20%,所有借钱事件(0 开头的操作)发生在所有询问事件(1 开头的操作)之前;

第三种:占 30%,对于一只企鹅 A,最多只有一只企鹅向 A 借钱;

第四种:占 40%,没有特殊性质,n、m 大小有一定梯度。

对于所有数据,满足:n ≤ 105 10 5 ,m ≤ 106 10 6 ,0 ≤ a, b, c ≤ n 且 a ≠ b。

时间限制: 1s 1 s

空间限制: 512MB 512 MB


一种比较显然的做法是每次暴力维护倍增数组
在数据随机的时候会被卡成zz
考虑怎么优化这个过程
启发式合并。
我们把树看成无根树,额外维护一个倍增数组表示走 2i 2 i 的了路径上的边的方向
这样就可以合并了。
复杂度 O(nlog2n) O ( n l o g 2 n )

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
const int INF = 1e9;
namespace fastIO{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror = 0;
    inline char nc(){
        static char buf[BUF_SIZE],*p1 = buf+BUF_SIZE, *pend = buf+BUF_SIZE;
        if(p1 == pend){
            p1 = buf; pend = buf+fread(buf, 1, BUF_SIZE, stdin);
            if(pend == p1){ IOerror = 1; return -1;}
        }
        return *p1++;
    }
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
    inline void read(int &x){
        bool sign = 0; char ch = nc(); x = 0;
        for(; blank(ch); ch = nc());
        if(IOerror)return;
        if(ch == '-') sign = 1, ch = nc();
        for(; ch >= '0' && ch <= '9'; ch = nc()) x = x*10+ch-'0';
        if(sign) x = -x;
    }
    inline void read(ll &x){
        bool sign = 0; char ch = nc(); x = 0;
        for(; blank(ch); ch = nc());
        if(IOerror) return;
        if(ch == '-') sign = 1, ch = nc();
        for(; ch >= '0' && ch <= '9'; ch = nc()) x = x*10+ch-'0';
        if(sign) x = -x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
int lastans,n,m;
int f[101000][20] , mn[101000][20] , di[101000][20];
int size[101000] , bel[101000] , dep[101000];
int linkk[101000],t;
struct node{
    int n , y , v , kind;
}e[201000];
int min(int a,int b) {return a>b?b:a;}
void add(int x,int y,int z)
{
    e[++t].y = y;e[t].n = linkk[x];e[t].v = z;e[t].kind = 1;linkk[x] = t; 
    e[++t].y = x;e[t].n = linkk[y];e[t].v = z;e[t].kind = 2;linkk[y] = t;
} 
void dfs(int x,int fa,int root)
{
    bel[x] = root;
    dep[x] = dep[fa] + 1;
    rep(i,1,17)  
        f[x][i] = f[f[x][i-1]][i-1],
        mn[x][i] = min(mn[x][i-1],mn[f[x][i-1]][i-1]),
        di[x][i] = di[x][i-1] | di[f[x][i-1]][i-1];
    rept(i,x)
        if(e[i].y != fa)
        {
            int y = e[i].y;
            f[y][0] = x;
            mn[y][0] = e[i].v;
            di[y][0] = e[i].kind ^ 3;
            dfs(y,x,root);
        }
}
void insert(int a,int b,int c) 
{
    add(a,b,c);
    int d = (size[bel[a]] > size[bel[b]]) ? 2 : 1;
    if(d == 2) swap(a,b);
    size[bel[b]] += size[bel[a]];
    f[a][0] = b;mn[a][0] = c;di[a][0] = d;
    dfs(a,b,bel[b]);
}
int query(int x,int y)
{
    int d = 1;
    if(dep[x] < dep[y]) swap(x,y) , d=2;
    int ans = INF;
    repp(i,17,0)
        if(dep[x] - (1<<i) >= dep[y]) 
        {
            if(di[x][i] != d) return 0;
            ans = min(ans,mn[x][i]);
            x = f[x][i];
        }
    if(x == y) return ans;
    repp(i,17,0)
        if(f[x][i] != f[y][i])
        {
            if(di[x][i] != d || di[y][i] != (d ^ 3)) return 0;
            ans = min(ans , min(mn[x][i] , mn[y][i]));
            x = f[x][i];y = f[y][i]; 
        }
    if(di[x][0] != d || di[y][0] != (d^3)) return 0;
    ans = min(ans,min(mn[x][0],mn[y][0]));
    return ans;
} 
int main()
{
    freopen("money.in","r",stdin);
    freopen("money.out","w",stdout);
    read(n);read(m);rep(i,1,n) bel[i] = i,size[i] = 1;
    rep(i,1,m)
    {
        int kind,a,b,c;
        read(kind);read(a);read(b);
        a = (a + lastans)%n+1;
        b = (b + lastans)%n+1; 
        if(kind == 0) read(c),c = (c + lastans)%n+1,insert(a,b,c); 
        else printf("%d\n",lastans=query(a,b));
    }
    return 0;
}

还有一种比较神的做法是用vector存同一深度的点再用链表串起来,再启发式合并,能优化掉一个 log l o g

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值