• JZOJ 6273. 2019.8.4【NOIP提高组A】欠钱(树上倍增+带权并查集)


    JZOJ 6273. 2019.8.4【NOIP提高组A】欠钱

    题目

    Description

    在这里插入图片描述

    Input

    第一行两个整数 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。

    Output

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

    Sample 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

    Sample Output

    3
    2
    0
    1
    0

    Data Constraint在这里插入图片描述

    题解

    • 简化一下题目:
    • 有一个森林(多棵树),初始状态没有连边,给出
    • 0 0 0:儿子 a a a往父亲 b b b连一条边权为 c c c单向边
    • 1 1 1:询问 x x x y y y的路径(有向)中,边权最小是多少,若不可到达则输出 0 0 0
    • 题目强制在线。。。(离线好像容易许多)
    • 据说这是一道 L C T LCT LCT的裸题(但会被卡),然而并不需要,而且时间还快得多~~~
    • 先考虑暴力做法,
    • 用倍增来进行询问求值,每次连边时暴力更新子树内倍增数组的值,还要更新子树内每个节点的深度,
    • 同时还可以记录 h [ i ] h[i] h[i]表示倍增数组的 f [ i ] [ j ] f[i][j] f[i][j] i i i节点向上 2 j 2^j 2j步)中的 j j j已经更新过 0 − h [ i ] 0-h[i] 0h[i]的值了,之后再更新直接从 h [ i ] h[i] h[i] log ⁡ 2 n log_2 n log2n,可以优化时间,
    • 这样的时间复杂度还是 O ( n 2 ) O(n^2) O(n2)的,超时!!!
    • 我们发现,倍增数组只是对询问有用(废话,更新不就是为了询问嘛——),
    • 那么可以试试询问时再来修改,
    • 但先需要在连边时用带权并查集维护节点的深度,否则无法倍增,
    • 然后询问时直接按普通的倍增向上跳,有遇到没有更新的就递归更新
    • 也就是看 f [ i ] [ j − 1 ] f[i][j-1] f[i][j1] f [ f [ i ] [ j − 1 ] ] [ j − 1 ] f[f[i][j-1]][j-1] f[f[i][j1]][j1]分别有没有值,没有就继续递归下去,有就返回更新上一层的。
    • 需要读入优化。
    • 这道题运用到了一种很普遍的思想:
    • 不急于每次修改就把所有的需要更新的更新,而是等到它需要使用时再来更新,这样可以一定程度上节约时间。
    • 并查集类似如此(每次连边时儿子指向父亲,用到每个节点时再来压缩路径)。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 100010
    int f[N][20],g[N][20],dp[N],r[N],rs[N];
    int get(int v)
    {
    	if(r[v]==v) 
    	{
    		rs[v]=0;
    		return v;
    	}
    	int rt=get(r[v]);
    	rs[v]+=rs[r[v]];
    	r[v]=rt;
    	return r[v];
    }
    void count(int v,int i)
    {
    	if(i==0) return;
    	if(f[v][i]) return;
    	count(v,i-1);
    	count(f[v][i-1],i-1);
    	f[v][i]=f[f[v][i-1]][i-1];
    	g[v][i]=min(g[v][i-1],g[f[v][i-1]][i-1]);
    }
    int read()
    {
    	int t=0;
    	char c=getchar();
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') t=t*10+c-'0',c=getchar();
    	return t;
    }
    int main()
    {
    	int n,Q,i,k,x,y,c,ls=0;
    	scanf("%d%d",&n,&Q);
    	for(i=1;i<=n;i++) r[i]=i;
    	while(Q--)
    	{
    		k=read();
    		if(k)
    		{
    			x=read(),y=read();
    			x=(x+ls)%n+1;
    			y=(y+ls)%n+1;
    			get(x);
    			get(y);
    			int ans=1e+9;
    			for(i=19;i>=0;i--) 
    			{
    				get(x);
    				if(rs[x]-(1<<i)>=rs[y])
    				{
    					count(x,i);
    					ans=min(ans,g[x][i]);
    					x=f[x][i];	
    				}
    				
    			}
    			if(x!=y) ans=0;
    			ls=ans;
    			printf("%d
    ",ls);
    		}
    		else
    		{
    			x=read(),y=read(),c=read();
    			x=(x+ls)%n+1;
    			y=(y+ls)%n+1;
    			c=(c+ls)%n+1;
    			f[x][0]=y;
    			g[x][0]=c;	
    			r[x]=y;
    			rs[x]=1;
    		}
    	}
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    POJ 2449 Remmarguts' Date(第k短路のA*算法)
    UESTC 1717 Journey(DFS+LCA)(Sichuan State Programming Contest 2012)
    HRBUST 1211 火车上的人数【数论解方程/模拟之枚举+递推】
    洛谷 P1372 又是毕业季I[数论/神坑规律题]
    洛谷 P1865 A % B Problem[筛素数/前缀和思想/区间质数个数]
    CCCC L2-003. 月饼[贪心/类似hdu贪心老鼠]
    二项式定理与杨辉三角
    Educational Codeforces Round 39 (Rated for Div. 2) B. Weird Subtraction Process[数论/欧几里得算法]
    洛谷 P1784 数独[DFS/回溯]
    Wannafly交流赛1 B 硬币[数学思维/贪心]
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910070.html
Copyright © 2020-2023  润新知