Believe it

相信不屈不挠的努力,相信战胜死亡的年轻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// tree 节点0不准使用
int head[maxn];// point
int to[maxn*2],nex[maxn*2],tot;// edge
inline void _addedge(int u,int v){to[++tot]=v,nex[tot]=head[u],head[u]=tot;}
inline void addedge(int u,int v){_addedge(u,v),_addedge(v,u);}
void deltree(int rt,int father){// deltree() and also don't forget tot
for(int i=head[rt];i;i=nex[i]) if(to[i]!=father) deltree(to[i],rt);
head[rt]=0;
}
// struct tree{int rt,n;}


//tree hash
int pw[maxn*2]={1},hshmod;//pw要两倍
int *hsh,siz[maxn]; //point
int *ehsh; //edge
void dfs(int u,int father){
siz[u]=1;
for(int i=head[u];i;i=nex[i]){
if(to[i]==father)continue;
dfs(to[i],u), siz[u]+=siz[to[i]];
}
}
void dfs1(int u,int father){// solve every edge from father->u
for(int i=head[u];i;i=nex[i]){
if(to[i]==father) continue;
dfs1(to[i],u);

vector<pii>buf;
for(int j=head[to[i]];j;j=nex[j]){
if(to[j]==u) continue;
buf.emplace_back(ehsh[j],2*siz[to[j]]);
}
sort(buf.begin(),buf.end());
ehsh[i]=1;// 左边放1
for(pii x:buf) ehsh[i]=(1ll*ehsh[i]*pw[x.second]+x.first)%hshmod;
ehsh[i]=(1ll*ehsh[i]*pw[1]+2)%hshmod;// 右边放2
}
}
void dfs2(int u,int father,int rt){
vector<pii>buf;
for(int i=head[u];i;i=nex[i]) {
if(to[i]==father) buf.emplace_back(ehsh[i],2*(siz[rt]-siz[u]));
else buf.emplace_back(ehsh[i],2*siz[to[i]]);
}
sort(buf.begin(),buf.end());
hsh[u]=1;// 左边放1
for(pii x:buf) hsh[u]=(1ll*hsh[u]*pw[x.second]+x.first)%hshmod;
hsh[u]=(1ll*hsh[u]*pw[1]+2)%hshmod;// 右边放2

vector<pii>pre(buf),suf(buf);// 对后面进行处理
int sz=suf.size();
for(int i=1,j=sz-2;i<sz;i++,j--){
pre[i].first=(1ll*pre[i-1].first*pw[pre[i].second]+pre[i].first)%hshmod;// merge i-1 and i
suf[j].first=(1ll*suf[j].first*pw[suf[j+1].second]+suf[j+1].first)%hshmod;// merge j and j+1
pre[i].second+=pre[i-1].second;
suf[j].second+=suf[j+1].second;
}

for(int i=head[u];i;i=nex[i]){
if(father==to[i]) continue;
ehsh[i^1]=1;//左边放1
int idx=lower_bound(buf.begin(),buf.end(),pii(ehsh[i],2*siz[to[i]]))-buf.begin();
if(idx-1>=0) ehsh[i^1]=(1ll*ehsh[i^1]*pw[pre[idx-1].second]+pre[idx-1].first)%hshmod;// 前缀
if(idx+1<sz) ehsh[i^1]=(1ll*ehsh[i^1]*pw[suf[idx+1].second]+suf[idx+1].first)%hshmod;// 后缀
ehsh[i^1]=(1ll*ehsh[i^1]*pw[1]+2)%hshmod;//右边放2
dfs2(to[i],u,rt);
}
}
void treehash(int u,int*hsh_,int*ehsh_,int base,int hshmod_){//hash all tree of tree u
hsh=hsh_,ehsh=ehsh_,hshmod=hshmod_;
dfs(u,0); for(int i=1;i<=siz[u]*2;i++) pw[i]=1ll*pw[i-1]*base%hshmod;
dfs1(u,0),dfs2(u,0,u);
}
////// end

广义斐波那契数递推公式 \[f_i=af_{i-1}+bf_{i-2}(\mod p) (p是奇素数)\]

他的转移矩阵 $$ ^n

p=

$$

如果存在循环节则存在n使得 \[ \left[ \begin{matrix} a & b \\ 1 & 0 \end{matrix} \right]^n= \left[ \begin{matrix} k_1p+1 & k_2p+0 \\ k_3p+0 & k_4p+1 \end{matrix} \right] \]

我们尝试把左边变成相似对角矩阵 先求特征值 \[ (\lambda-a)\lambda-b=0 \Leftrightarrow \lambda=\frac{a\pm\sqrt{a^2+4b}}{2} \]

当且仅当\(a^2+4b=0\)的时候,\(\lambda_1=\lambda_2\),易证尽管此时\(\lambda\)是二重特征值,但是它对应的特征向量只有一个,即上诉矩阵不可对角化,我们不考虑这种复杂的情况。 当\(a^2+4b\neq0\)的时候,两个特征向量分别为 \[ \left[ \begin{matrix} \lambda_1 \\ 1 \end{matrix} \right] 和 \left[ \begin{matrix} \lambda_2 \\ 1 \end{matrix} \right] \] 那么就有了 \[ \left[ \begin{matrix} a & b \\ 1 & 0 \end{matrix} \right]= \left[ \begin{matrix} \lambda_1 & \lambda_2 \\ 1 & 1 \end{matrix} \right] \left[ \begin{matrix} \lambda_1 & 0 \\ 0 & \lambda_2 \end{matrix} \right] \left[ \begin{matrix} \frac{1}{\lambda_1-\lambda_2} & \frac{-\lambda_2}{\lambda_1-\lambda_2} \\ \frac{-1}{\lambda_1-\lambda_2} & \frac{\lambda_1}{\lambda_1-\lambda_2} \end{matrix} \right] \] 进而有了 \[ \left[ \begin{matrix} \lambda_1 & \lambda_2 \\ 1 & 1 \end{matrix} \right] \left[ \begin{matrix} \lambda_1^n & 0 \\ 0 & \lambda_2^n \end{matrix} \right] \left[ \begin{matrix} \frac{1}{\lambda_1-\lambda_2} & \frac{-\lambda_2}{\lambda_1-\lambda_2} \\ \frac{-1}{\lambda_1-\lambda_2} & \frac{\lambda_1}{\lambda_1-\lambda_2} \end{matrix} \right]= \left[ \begin{matrix} k_1p+1 & k_2p+0 \\ k_3p+0 & k_4p+1 \end{matrix} \right] \] 右乘\(T\)消掉那个一堆分数的矩阵 \[ \left[ \begin{matrix} \lambda_1 & \lambda_2 \\ 1 & 1 \end{matrix} \right] \left[ \begin{matrix} \lambda_1^n & 0 \\ 0 & \lambda_2^n \end{matrix} \right]= \left[ \begin{matrix} k_1p+1 & k_2p+0 \\ k_3p+0 & k_4p+1 \end{matrix} \right] \left[ \begin{matrix} \lambda_1 & \lambda_2 \\ 1 & 1 \end{matrix} \right] \] 乘开 \[ \left[ \begin{matrix} \lambda_1^{n+1} & \lambda_2^{n+1} \\ \lambda_1^{n} & \lambda_1^{n} \end{matrix} \right]= \left[ \begin{matrix} \lambda_1(k_1p+1)+k_2p & \lambda_2(k_1p+1)+k_2p \\ \lambda_1k_3p+k_4p+1 & \lambda_2k_3p+k_4p+1 \end{matrix} \right] \] ###在这之后我们分两部分讨论 ####\(a^2+4b是二次剩余\) 如果\(a^2+4b\)是二次剩余,那么\(\lambda_1\)\(\lambda_2\)可以直接写成模意义下对应的整数,则上诉矩阵等式在\(n=p-1\)的时候根据费马小定理恒成立 ####\(a^2+4b不是二次剩余\) 在这里,是绝对不能够直接取模的,因为\(\lambda\)中一旦包含了根号下非二次剩余,这里就是错的,我们不可以取模,直接用根式表达即可。 #####两矩阵相等条件1: \[ \lambda^n=\lambda k_3p+k_4p+1 \] 先看\(\lambda_1\) \[ \lambda_1=\frac{a+\sqrt{a^2+4b}}{2}=\frac{a}{2}+\frac{1}{2}\sqrt{a^2+4b} \]\[ (\frac{a}{2}+\frac{1}{2}\sqrt{a^2+4b})^n=(\frac{a}{2}+\frac{1}{2}\sqrt{a^2+4b})k_3p+k_4p+1 \] 分母有点难受,把它移到右边去 \[ (a+\sqrt{a^2+4b})^n=2^n* ((\frac{a}{2}+\frac{1}{2}\sqrt{a^2+4b})k_3p+k_4p+1)\\ \sum_{i=0}^nC_n^ia^i\sqrt{a^2+4b}^{n-i}=2^n* (\frac{a}{2}k_3p+k_4p+1)+2^n* (\frac{1}{2}k_3p)\sqrt{a^2+4b} \] 我们在这里引入一些概念,我们在实数领域解决这个问题,在实数领域,我们把数分为两部分来表示,一部分是有理数部分,称之为有理部,另一部分是无理数部分,称之为无理部,即\(1+2\sqrt{16}\)中,我们称1为有理部,2位无理部。 上式左边显然能够唯一表示为\(x+y\sqrt{a^2+4b}\),那么两式相等的充要条件就是 \[ 存在k_3,k_4使得x=2^n* (\frac{a}{2}k_3p+k_4p+1), y=2^n* \frac{1}{2}k_3p \] 上面的式子的某个充分条件为 \[ \frac{x}{2^n} \equiv1 \mod p\\ \frac{y}{2^n} \equiv0 \mod p \] 更加具体一点如果n是(p-1)的倍数则下面的式子也是充分条件 \[ x \equiv1 \mod p\\ y \equiv0 \mod p \] 为了利用这点,我们保证后面n一定是p-1的倍数,让我们先遗忘掉这些充分条件

然后我们来看看这个规律,注意到\(\sum_{i=0}^nC_n^ia^i\sqrt{a^2+4b}^{n-i}\)中,当\(n=p且i\neq0且i\neq n\)的时候,\(C_n^i|p\),所以 \[ x\equiv a^p \equiv a\\ y\equiv \sqrt{a^2+4b}^p \]\[ \begin{aligned} &(a+\sqrt{a^2+4b})^p \\=&(a+c_1p)+(\sqrt{a^2+4b}^{p-1}+c_2p)\sqrt{a^2+4b},c_1c_2是整数 \\=& (a+c_1p)+((a^2+4b)^{\frac{p-1}{2}}+c_2p)\sqrt{a^2+4b} \\=& a+(a^2+4b)^{\frac{p-1}{2}}\sqrt{a^2+4b}+c_1p+c_2p\sqrt{a^2+4b} \end{aligned} \] 这时候因为\(a^2+4b\)是一个非二次剩余,所以上式可以表达为 \[ a-\sqrt{a^2+4b}+c_1p+c_2p\sqrt{a^2+4b} \] 我们让他乘上\(\frac{a+\sqrt{a^2+4b}}{2}\),他的无理部就彻底与0同余了,此时的\(n=(p+1)\),在让这个数幂上\(p-1\),他的有理部就与1同余了,并且我们达到了之前的约定,n是p-1的倍数,此时的\(n=(p+1)(p-1)\) #####两矩阵相等条件2: \[ \begin{aligned} &\lambda^{n+1}=\lambda(k_1p+1)+k_2p\\ \Leftrightarrow&\lambda^{n+1}=(\frac{a}{2}+\frac{1}{2}\sqrt{a^2+4b})(k_1p+1)+k_2p\\ \Leftrightarrow&\lambda^{n+1}=(\frac{a}{2}+\frac{1}{2}\sqrt{a^2+4b})+\frac{a}{2}k_1p+\frac{1}{2}\sqrt{a^2+4b}k_1pk_2p+k_2p \end{aligned} \] 之前我们证明了\(\lambda^{(p+1)(p-1)}\)的有理部与1同余,无理部与0同余,这里显然\(\lambda^{(p+1)(p-1)+1}\)的有理部与\(\frac{a}{2}\)同余,无理部与\(\frac{1}{2}\)同余, 至于\(\lambda_2\)是同理的。

至此证明了当\(a^2+4b\)是二次剩余的时候,循环节至多为\(n-1\),当\(a^2+4b\)不是二次剩余的时候,循环节至多为\(n^2-1\)\(a^2+4b=0\)的时候还有待挖掘

###name the power of Fibonacci

###description Amy asks Mr. B problem A. Please help Mr. B to solve the following problem. Let Fi be fibonacci number. \(F_0 = 0, F_1 = 1, F_i = F_{i-1} + F_{i-2}\) Given n and m, please calculate \(\sum^n_{i=0}{F_i^m}\)
As the answer might be very large, output it module 1000000000.

###input The first and only line contains two integers n, m(1 <= n <= 1000000000, 1 <= m <= 1000).

###output Output a single integer, the answer module 1000000000.

###sample input 1 5 5

###sample output 1 3402

###sample input 2 10 10

###sample output 2 696237975

###sample input 3 1000000000 1000

###sample output 3 641796875

###toturial 对\(10^9\)进行分解,\(10^9=2^9\*5^9\),然后打表,分别找到循环节的长度,最后用中国剩余定理合并

###code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
const int len5=7812500,len2=768;
int fib5[len5+1],fib2[len2+1];

int qpow(int a,int b,int mod){
int res=1;
for(;b;b>>=1,a=1ll*a*a%mod) if(b&1)res=1ll*res*a%mod;
return res;
}

void Exeuclid(ll a, ll& x, ll b, ll& y, ll c){
if (!b) { x = c / a, y = 0; }
else {
Exeuclid(b, x, a % b, y, c);
x -= a / b * y;
swap(x, y);
}
}

int merge(int x1,int p1,int x2,int p2){
// u*p1+x1=v*p2+x2
// u*p1-v*p2=x2-x1
ll u,v;
Exeuclid(p1,u,p2,v,x2-x1);
ll p=p1*p2;
return ((u*p1+x1)%p+p)%p;
}

int main(){
// cout<<1ll*len5/__gcd(len5,len2)*len2<<endl;
fib2[1]=fib2[2]=fib5[1]=fib5[2]=1;
rep(i,3,len2) fib2[i]=(fib2[i-1]+fib2[i-2])%512;
rep(i,3,len5) fib5[i]=(fib5[i-1]+fib5[i-2])%1953125;
int n,m; scanf("%d%d",&n,&m);
rep(i,1,len2) fib2[i]=(qpow(fib2[i],m,512)+fib2[i-1])%512;
rep(i,1,len5) fib5[i]=(qpow(fib5[i],m,1953125)+fib5[i-1])%1953125;
int ans2=(1ll*fib2[len2]*(n/len2)+fib2[n%len2])%512;
int ans5=(1ll*fib5[len5]*(n/len5)+fib5[n%len5])%1953125;
printf("%d\n",merge(ans2,512,ans5,1953125));
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define I __int128
void exgcd(I a,I&x,I b,I&y,I c){ // assert(__gcd(a,b)==c)
if(b==0) x=c/a,y=0;
else exgcd(b,y,a%b,x,c),y-=a/b*x;
}

inline bool merge(I x1,I p1,I x2,I p2,I&x,I&p){
I a,b,d=__gcd(p1,p2);// ap1+x1=bp2+x2 a+k(p2/gcd)
if((x2-x1)%d!=0) return false;
exgcd(p1,a,p2,b,x2-x1);
p=p1/d*p2; //lcm
x=((a*p1+x1)%p+p)%p;//
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
static BigInteger[] exgcd(BigInteger a, BigInteger b, BigInteger c) { // ax+by=c res[0]=x,res[1]=y
if (b.compareTo(BigInteger.ZERO) == 0) return new BigInteger[]{c.divide(a), BigInteger.ZERO};
BigInteger[] r = exgcd(b, a.mod(b), c);
return new BigInteger[]{r[1], r[0].subtract(a.divide(b).multiply(r[1]))};
}

static BigInteger[] merge(BigInteger x1, BigInteger p1, BigInteger x2, BigInteger p2) {
BigInteger d = p1.gcd(p2);
if (x2.subtract(x1).mod(d).compareTo(BigInteger.ZERO) != 0) return null;
BigInteger[] r = exgcd(p1, p2, x2.subtract(x1));
BigInteger p = p1.divide(d).multiply(p2); // p=p1/d*p2
BigInteger x=r[0].multiply(p1).add(x1).mod(p).add(p).mod(p);
return new BigInteger[]{x, p};
}
}

虚树就是把树上一些节点拿下来重新建树,插入一些lca之类的点,deltree会删除一颗树,但不会删掉他的边,所以要注意边的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// tree 节点0不准使用
const int maxn=5e5+5;
int head[maxn];// point
int to[maxn*2],ew[maxn*2],nex[maxn*2],tot;// edge
inline void _addedge(int u,int v,int w){to[++tot]=v,ew[tot]=w,nex[tot]=head[u],head[u]=tot;}
inline void addedge(int u,int v,int w){_addedge(u,v,w),_addedge(v,u,w);}
void deltree(int rt,int father){// deltree() and also don't forget 还原tot
for(int i=head[rt];i;i=nex[i]) if(to[i]!=father) deltree(to[i],rt);
head[rt]=0;
}

// 树剖lca
int dep[maxn],dad[maxn],siz[maxn],son[maxn],dfn[maxn],chain[maxn],step;
void dfs1(int u,int father){// dfs(1,0)
siz[u]=1; son[u]=0; dad[u]=father; dep[u]=dep[father]+1;
for(int i=head[u];i;i=nex[i]){
if(to[i]==father) continue;
dfs1(to[i],u);
siz[u]+=siz[to[i]];
if(siz[to[i]]>siz[son[u]]) son[u]=to[i]; // don't care son=0 because siz[0]=0
}
}
void dfs2(int u,int s){// dfs(1,1) step=0 at begin
dfn[u]=++step; chain[u]=s;
if(son[u]) dfs2(son[u],s);
for(int i=head[u];i;i=nex[i]){
if(to[i]==dad[u]||to[i]==son[u]) continue;
dfs2(to[i],to[i]);
}
}
int getlca(int x,int y){
while(chain[x]!=chain[y]) {
if(dep[chain[x]]<dep[chain[y]]) swap(x,y);
x=dad[chain[x]];
}
return dep[x]<dep[y]?x:y;
}

// virtual tree
bool vt[maxn];// point
void buildvt(int*vert,int nums,int base){// vert -> [1,nums]
sort(vert+1,vert+nums+1,[](int x,int y){return dfn[x]<dfn[y];});
int top=0;
stk[++top]=1,vt[base+1]=vert[1]==1; // root
rep(i,vert[1]==1?2:1,nums){
int lca=getlca(vert[i],stk[top]);
if(lca==stk[top]) {stk[++top]=vert[i],vt[base+vert[i]]=true;continue;}//还在链上
while(dfn[lca]<=dfn[stk[top-1]]) addedge(base+stk[top],base+stk[top-1],0),top--;
if(lca!=stk[top]) addedge(base+stk[top],base+lca,0),stk[top]=lca,vt[base+lca]=false;
stk[++top]=vert[i],vt[base+vert[i]]=true;
}
while(top>=2){
addedge(base+stk[top],base+stk[top-1],0);
top--;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
typedef long long ll;
struct cp{
static ll p,w;
ll x,y;// x+y\sqrt(w)
cp(ll x,ll y):x(x),y(y){}
cp operator*(cp rhs){
return cp((x*rhs.x+y*rhs.y%p*w)%p,(x*rhs.y+y*rhs.x)%p);
}
};
ll cp::p,cp::w;

cp qpow(cp a,ll b){
cp res(1,0);
for(;b;b>>=1,a=a*a) if(b&1)res=res*a;
return res;
}
ll qpow(ll a,ll b,ll p){
ll res=1;
for(;b;b>>=1,a=a*a%p) if(b&1)res=res*a%p;
return res;
}
ll sqrt(ll x,ll p){ // return sqrt(x)%p
if(x==0) return 0;
if(qpow(x,(p-1)/2,p)==p-1)return -1;
ll a=1,w=(1-x+p)%p;
while(qpow(w,(p-1)/2,p)!=p-1) ++a,w=(a*a-x+p)%p;
cp::w=w,cp::p=p;
return qpow(cp(a,1),(p+1)/2).x;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
int top,c[N][2],f[N],tim[N],sta[N],rev[N],val[N];
void ini(){
for(int i=0;i<=n;i++)c[i][0]=c[i][1]=f[i]=rev[i]=0,tim[i]=i,val[i]=2e9;
for(int i=n+1;i<=n+m;i++)c[i][0]=c[i][1]=f[i]=rev[i]=0,tim[i]=i,val[i]=R[i-n];
}
inline void pushup(int x){
tim[x]=x;
if(val[tim[c[x][0]]]<val[tim[x]]) tim[x]=tim[c[x][0]];
if(val[tim[c[x][1]]]<val[tim[x]]) tim[x]=tim[c[x][1]];
}
inline void pushdown(int x){
int l=c[x][0],r=c[x][1];
if(rev[x]){
rev[l]^=1;rev[r]^=1;rev[x]^=1;
swap(c[x][0],c[x][1]);
}
}
inline bool isroot(int x){return c[f[x]][0]!=x&&c[f[x]][1]!=x;}
inline void rotate(int x){
int y=f[x],z=f[y],xis=c[y][1]==x,yis=c[z][1]==y;//
if(!isroot(y)) c[z][yis]=x;//son
f[x]=z;f[y]=x;f[c[x][xis^1]]=y;//father
c[y][xis]=c[x][xis^1];c[x][xis^1]=y;//son
pushup(y);
}
inline void splay(int x){
top=1;sta[top]=x;//init stack
for(int i=x;!isroot(i);i=f[i])sta[++top]=f[i];//update stack
for(int i=top;i;i--)pushdown(sta[i]);//pushroad
while(!isroot(x)){
int y=f[x],z=f[y];
if(!isroot(y)) (c[y][0]==x)^(c[z][0]==y)?rotate(y):rotate(x);
rotate(x);
}pushup(x);
}
inline void access(int x){for(int t=0;x;t=x,x=f[x])splay(x),c[x][1]=t,pushup(x);}
inline int treeroot(int x){access(x);splay(x);while(c[x][0])x=c[x][0];return x;}
inline void makeroot(int x){access(x);splay(x);rev[x]^=1;}// 让x变成根
inline void cut(int x,int y){makeroot(x);access(y);splay(y);f[x]=c[y][0]=0;pushup(y);}
inline void link(int x,int y){makeroot(x);f[x]=y;}

###name explorer

###description Gromah and LZR have entered the fifth level. Unlike the first four levels, they should do some moves in this level.

There are nvertices and m bidirectional roads in this level, each road is in format (u,v,l,r) , which means that vertex u and v are connected by this road, but the sizes of passers should be in interval [l,r] . Since passers with small size are likely to be attacked by other animals and passers with large size may be blocked by some narrow roads.

Moreover, vertex 1 is the starting point and vertex n is the destination. Gromah and LZR should go from vertex 1 to vertex n to enter the next level.

At the beginning of their exploration, they may drink a magic potion to set their sizes to a fixed positive integer. They want to know the number of positive integer sizes that make it possible for them to go from 1 to n .

Please help them to find the number of valid sizes.

###input The first line contains two positive integers n,m , denoting the number of vertices and roads. Following m lines each contains four positive integers u,v,l,r , denoting a bidirectional road (u,v,l,r) . \(1≤n,m≤10^5 ,1≤u\lt v≤n,1≤l≤r≤10^9\)

###output Print a non-negative integer in a single line, denoting the number of valid sizes.

###sample input 5 5 1 2 1 4 2 3 1 2 3 5 2 4 2 4 1 3 4 5 3 4

###sample output 2

###hint There are 2 valid sizes : 2 and 3. For size 2, there exists a path 1→2→3→5. For size 3, there exists a path 1→2→4→5.

###toturial 把l,r看作限制,从小到大枚举区间,则表现为删边加边,然后问图的联通情况。这可以用直接lct维护。

###code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include<bits/stdc++.h>
using namespace std;

static const int N=4e5+555;
int X[N],Y[N],L[N],R[N],sa[2][N];
int n,m;

int top,c[N][2],f[N],tim[N],sta[N],rev[N],val[N];
void ini(){
for(int i=0;i<=n;i++)c[i][0]=c[i][1]=f[i]=rev[i]=0,tim[i]=i,val[i]=2e9;
for(int i=n+1;i<=n+m;i++)c[i][0]=c[i][1]=f[i]=rev[i]=0,tim[i]=i,val[i]=R[i-n];
}
inline void pushup(int x){
tim[x]=x;
if(val[tim[c[x][0]]]<val[tim[x]]) tim[x]=tim[c[x][0]];
if(val[tim[c[x][1]]]<val[tim[x]]) tim[x]=tim[c[x][1]];
}
inline void pushdown(int x){
int l=c[x][0],r=c[x][1];
if(rev[x]){
rev[l]^=1;rev[r]^=1;rev[x]^=1;
swap(c[x][0],c[x][1]);
}
}
inline bool isroot(int x){return c[f[x]][0]!=x&&c[f[x]][1]!=x;}
inline void rotate(int x){
int y=f[x],z=f[y],xis=c[y][1]==x,yis=c[z][1]==y;//
if(!isroot(y)) c[z][yis]=x;//son
f[x]=z;f[y]=x;f[c[x][xis^1]]=y;//father
c[y][xis]=c[x][xis^1];c[x][xis^1]=y;//son
pushup(y);
}
inline void splay(int x){
top=1;sta[top]=x;//init stack
for(int i=x;!isroot(i);i=f[i])sta[++top]=f[i];//update stack
for(int i=top;i;i--)pushdown(sta[i]);//pushroad
while(!isroot(x)){
int y=f[x],z=f[y];
if(!isroot(y)) (c[y][0]==x)^(c[z][0]==y)?rotate(y):rotate(x);
rotate(x);
}pushup(x);
}
inline void access(int x){for(int t=0;x;t=x,x=f[x])splay(x),c[x][1]=t,pushup(x);}
inline int treeroot(int x){access(x);splay(x);while(c[x][0])x=c[x][0];return x;}
inline void makeroot(int x){access(x);splay(x);rev[x]^=1;}// 让x变成根
inline void cut(int x,int y){makeroot(x);access(y);splay(y);f[x]=c[y][0]=0;pushup(y);}
inline void link(int x,int y){makeroot(x);f[x]=y;}
inline void cut2(int i){
makeroot(X[i]);
if(treeroot(Y[i])!=X[i]) return;
cut(X[i],n+i),cut(Y[i],n+i);
}
inline void link2(int i){
makeroot(X[i]);
if(treeroot(Y[i])==X[i]) {// access(y) splay(y)
int p=tim[Y[i]]-n;
if(R[p]>=R[i]) return;// 这个非常重要
cut(X[p],n+p),cut(Y[p],n+p);
}
link(X[i],n+i),link(Y[i],n+i);
}

int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d%d%d",X+i,Y+i,L+i,R+i),sa[0][i]=sa[1][i]=i;
ini();

sort(sa[0]+1,sa[0]+1+m,[](int a,int b){return L[a]<L[b];});
sort(sa[1]+1,sa[1]+1+m,[](int a,int b){return R[a]<R[b];});
vector<int>disc;
for(int i=1;i<=m;i++) disc.push_back(L[i]),disc.push_back(R[i]+1);// [)
sort(disc.begin(),disc.end());
disc.erase(unique(disc.begin(),disc.end()),disc.end());

int ans=0;
for(int t=0,i=1,j=1;t<disc.size();t++){// [T,T+1)
while(i<=m&&L[sa[0][i]]==disc[t]) link2(sa[0][i++]);
while(j<=m&&R[sa[1][j]]+1==disc[t]) cut2(sa[1][j++]);
makeroot(1);if(treeroot(n)==1) ans+=disc[t+1]-disc[t];
}
cout<<ans<<endl;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const int maxn=1e5+5;
int to[maxn<<1],nex[maxn<<1],head[maxn],w[maxn],cnt;
void ini(){cnt=-1;for(int i=0;i<=n;i++) head[i]=-1;}
void add_edge(int u,int v){to[++cnt]=v;nex[cnt]=head[u];head[u]=cnt;}

int dep[maxn],dad[maxn],siz[maxn],son[maxn],chain[maxn],dfn[maxn];//
void dfs1(int u,int father){//dfs1(1,0)
dep[u]=dep[father]+1;//ini because dep[0]=1
dad[u]=father, siz[u]=1, son[u]=-1;
for(int i=head[u];~i;i=nex[i]){
int v=to[i];
if(v==father)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v;
}
}
void dfs2(int u,int s,int&step){
dfn[u]=++step;
chain[u]=s;
if(son[u]!=-1) dfs2(son[u],s,step);
for(int i=head[u];~i;i=nex[i]){
int v=to[i];
if(v!=son[u]&&v!=dad[u]) dfs2(v,v,step);
}
}
int query(int x,int y,int k){
int res=0;
while(chain[x]!=chain[y]){
if(dep[chain[x]]<dep[chain[y]]) swap(x,y); //dep[chain[x]]>dep[chain[y]]
res+=segtree::query(dfn[chain[x]],dfn[x],k);// [左,右,值]
x=dad[chain[x]];
}
if(dep[x]>dep[y]) swap(x,y);// dep[x]<dep[y]
return res+segtree::query(dfn[x],dfn[y],k);// [左,右,值]
}