1. 程式人生 > >[2018.10.11 T3] 欠錢

[2018.10.11 T3] 欠錢

暫無連結

欠錢

題目描述

南極的企鵝王國大學中生活著 n n 只企鵝,作為 21 21 世紀的優秀大學生,企鵝們積極響應“大眾創業,萬眾創新”的號召,紛紛創業。但是創業需要資金,企鵝們最近手頭比較緊,只能互相借錢。
企鵝的借錢行為是有規律可循的:每隻企鵝只會借一次錢,並且只會從一隻企鵝那裡借錢。借錢關係中不存在環(即不存在類似“金企鵝欠銀企鵝錢,銀企鵝欠銅企鵝錢,銅企鵝欠金企鵝錢”這種情況)。
企鵝的還錢行為也是有規律可循的:每隻企鵝一旦新獲得了一筆錢,就會立刻用這筆錢儘可能償還自己欠的債務,直到債務償清或用光這筆錢。它只會使用新獲得的這筆錢,至於以前它有沒有錢、有多少錢,與還錢行為無關。
企鵝們經常會做美夢。在一隻企鵝 A

A 的夢裡,它夢見自己創業成功,一下子獲得了 + +\infty 元錢,於是(按照上文的還錢規則)它趕快把錢用來還債,接著拿到錢的那隻企鵝也趕快把錢用來還債……如此往復,直到所有獲得錢的企鵝都完成了還債操作。夢醒之後,它開心地把夢的內容告訴了另外一隻企鵝 B
B
,企鵝 B B 聽了,也很開心,於是它問道:在你的夢裡,我獲得了多少錢呢? (指 B B 去還債之前手裡的錢,包括後來用於還債的錢和還債後 B
B
手裡剩下的錢。 )
夢畢竟是夢,對實際的欠債情況沒有影響。

格式
輸入格式

第一行兩個整數 n n m m ,表示有 n n 只企鵝, m m 個操作。
接下來 m m 行,有兩種可能的格式:

  • 0   a   b   c 0\ a\ b\ c :修改操作,企鵝 a a 向企鵝 b b 借了 c c 元錢。
  • 1   a   b 1\ a\ b :查詢操作,詢問假如 a a 有了 + 1 +1 元錢,企鵝 b b 會淨收入多少錢。

本題強制線上,也就是說:對於每個操作輸入的變數 a , b , c a,b,c (如果沒有 c c ,那就只有 a , b a, b )都不是實際的 a , b , c a, b, c ,想獲得實際的 a , b , c a, b, c 應當經過以下操作:

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

其中, l a s t a n s lastans 是上一次詢問的答案。如果沒有上一次詢問, l a s t a n s lastans 0 0

輸出格式

對每個詢問操作,輸出一行一個數表示答案。

樣例
樣例輸入

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

樣例輸出

32010

資料範圍

資料分為以下幾種:
第一種:佔 10 % 10\% n 5000 n ≤ 5000 m 10000 m ≤ 10000
第二種:佔 20 % 20\% ,所有借錢事件( 0 0 開頭的操作)發生在所有詢問事件( 1 1 開頭的操作)之前;
第三種:佔 30 % 30\% ,對於一隻企鵝 A A ,最多隻有一隻企鵝向 A A 借錢;
第四種:佔 40 % 40\% ,沒有特殊性質, n m n、 m 大小有一定梯度。
對於所有資料,滿足: n 1 0 5 m 1 0 6 0 a , b , c n n ≤ 10^5, m ≤ 10^6, 0 ≤ a, b, c ≤ n a b a \neq b

題解

考場上沒看清題,以為是個 D A G \mathcal{DAG} ,於是沒去管,又被 T 1 \mathcal{T}1 毒瘤,最後沒有時間寫。。。

所以,你特麼為什麼要在 N O I P \mathcal{NOIP} 模擬賽 T 3 \mathcal{T}3 ,放一道 L C T \mathcal{LCT} 傻逼題呢???

我們只需要一棵維護鏈上最小值的有根 L C T \mathcal{LCT} 就能解決所有問題。

LCT.gif

程式碼
#include<bits/stdc++.h>
#define ls son[v][0]
#define rs son[v][1]
using namespace std;
const int M=2e5+5;
int son[M][2],dad[M],val[M],mn[M],n,m,tot;
bool notroot(int v){return son[dad[v]][0]==v||son[dad[v]][1]==v;}
void up(int v){mn[v]=min(val[v],min(mn[ls],mn[rs]));}
void spin(int v)
{
	int f=dad[v],ff=dad[f],k=son[f][1]==v,w=son[v][!k];
	if(notroot(f))son[ff][son[ff][1]==f]=v;son[v][!k]=f,son[f][k]=w;
	if(w)dad[w]=f;dad[f]=v,dad[v]=ff;
	up(f);
}
void splay(int v)
{
	for(int f,ff;notroot(v);spin(v))
	{
		f=dad[v],ff=dad[f];
		if(notroot(f))spin((son[f][0]==v)^(son[ff][0]==f)?v:f);
	}
	up(v);
}
int access(int v){int f=0;for(;v;v=dad[f=v])splay(v),rs=f,up(v);return f;}
void link(int x,int y){splay(x);dad[x]=y;}
void in(){scanf("%d%d",&n,&m);}
void ac()
{
	memset(val,127,sizeof(val));
	memset(mn,127,sizeof(mn));
	tot=n;
	for(int i=1,last=0,op,a,b,c;i<=m;++i)
	{
		scanf("%d%d%d",&op,&a,&b);
		a=(a+last)%n+1,b=(b+last)%n+1;
		if(op)access(b),(access(a)==b?(splay(b),printf("%d\n",last=min(val[b],mn[son[b][1]]))):(printf("%d\n",last=0)));
		else scanf("%d",&c),c=(c+last)%n+1,val[++tot]=c,mn[tot]=c,link(a,tot),link(tot,b);
	}
}
int main(){in(),ac();}