1. 程式人生 > >洛谷T31018 經典題丶改(LCT+離線)

洛谷T31018 經典題丶改(LCT+離線)

題目連結

真的是一個大好題啊!

QWQ首先我們考慮這種問題,如果直接線上做,估計應該是做不了,那我們是不是可以直接考慮離線。

將所有詢問都按照 r r 來排序。

然後依次加入每條邊,計算 a [ i

] < = n o w r a[i]<=nowr 的答案

離線下來之後呢。

我們對於依次加入的邊,實際上就相當於一個維護生成樹的過程,那麼qwq應該以什麼為關鍵字呢?

由於我們可以精妙的發現,對於 r r 不減(或者說不變)來說,編號小的邊總是比大的邊要沒用,因為既然 [ l +

x , r ] [l+x,r] 能使聯通的話,那麼 [ l , r ] [l,r] 也一定可以。

我們令每條邊的邊權是他的編號

那麼我們維護的就是一個最小邊權最大的生成樹

然後類似 t w o   p o i n t e r two \ pointer

對於每一個 i i ,我們都暴力把 r < = i r<=i 的指標++,然後看一下是否聯通,聯通的條件是 f i n d r o o t ( x ) = = f i n d r o o t ( y ) m n [ y ] > = l findroot(x)==findroot(y) 且 mn[y]>=l ,後面這項表示 x > y x->y 的路徑上最小的編號,要在他要求的 l l 之後才行。

QWQ嚶嚶嚶
還有一個問題一定要注意!!!
就是點的編號的問題。

我們一定要強制讓每個邊對應的點的編號是 i + n i+n ,不要忽略重邊和自環(如果你是用一個 t o t tot 記錄的話)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
const int maxn = 5e5+1e2;
const int maxm = maxn;
struct Node{
 int l,r,a,b,id;
};
Node a[maxn];
int ch[maxn][3];
int rev[maxn],fa[maxn];
int n,m,cnt;
int mn[maxn],mnpos[maxn];
int val[maxn];
int xx[maxm],yy[maxm];
int ans[maxn];
int k;
int son(int x)
{
 if (ch[fa[x]][0]==x) return 0;
 else return 1;
}
bool notroot(int x)
{
 if(!x) return 0; 
 return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
void update(int x) 
{
 if (!x) return;
 mn[x]=val[x];
 mnpos[x]=x;
 if (ch[x][0])
 {
  if (mn[x]>mn[ch[x][0]])
  {
   mn[x]=mn[ch[x][0]];
   mnpos[x]=mnpos[ch[x][0]];
  }
 }
 if (ch[x][1])
 {
  if(mn[x]>mn[ch[x][1]])
  {
   mn[x]=mn[ch[x][1]];
   mnpos[x]=mnpos[ch[x][1]];
  }
 }
}
void reverse(int x)
{
 swap(ch[x][0],ch[x][1]);
 rev[x]^=1;
}
void pushdown(int x)
{
 if(rev[x])
 {
  if (ch[x][0]) reverse(ch[x][0]);
  if (ch[x][1]) reverse(ch[x][1]);
  rev[x]=0;
 }
}
void rotate(int x)
{
 int y=fa[x],z=fa[y];
 int b=son(x),c=son(y);
 if (notroot(y)) ch[z][c]=x;
 fa[x]=z;
 ch[y][b]=ch[x][!b];
 fa[ch[x][!b]]=y;
 ch[x][!b]=y;
 fa[y]=x;
 update(y);
 update(x);
}
int st[maxn];
void splay(int x)
{
 int y=x,cnt=0;
 st[++cnt]=y;
 while (notroot(y)) y=fa[y],st[++cnt]=y;
 while (cnt) pushdown(st[cnt--]);
 while (notroot(x))
 {
  int y=fa[x],z=fa[y];
  int b=son(x),c=son(y);
  if (notroot(y))
  {
   if(b==c) rotate(y);
   else rotate(x); 
   } 
   rotate(x);
 }
 update(x); 
}
void access(int x)
{
 for (int y=0;x;y=x,x=fa[x])
 {
  splay(x);
     ch[x][1]=y;
     update(x);
 }
}
void makeroot(int x)
{
 access(x);
 splay(x);
 reverse(x);
}
int findroot(int x)
{ 
 access(x);
 splay(x);
 while (ch[x][0])
 {
  pushdown(x);
  x=ch[x][0];
    }
   // cout<<x<<endl; 
 return x;
}
void split(int x,int y)
{
 makeroot(x);
 access(y);
 splay(y);
}
void link(int x,int y)
{
 makeroot(x);
 if (findroot(y)!=x)
 {
  fa[x]=y;
 }
}
void cut(int x,int y)
{
 split(x,y);
 if (ch[x][0] || ch[x][1] || fa[x]!=y || ch[y][1]) return;
 fa[x]=ch[y][0]=0;
 update(y);
}
bool cmp(Node a,Node b)
{
 return a.r<b.r;
}
int main()
{
  val[0]=1e9;
  n=read(),m=read(),k=read();
  for (int i=1;i<=n;i++) val[i]=1e9;
  for (int i=1;i<=m;i++) xx[i]=read(),yy[i]=read();
  for (int i=1;i<=k;i++)
  {
    a[i].l=read();
    a[i].r=read();
    a[i].a=read();
  a[i].b=read();
  a[i].id=i; 
  }
  sort(a+1,a+1+k,cmp);
  int tot=n;
  int now=1;
  for (int i=1;i<=m && now<=k;i++)
  {
    int x = xx[i],y=yy[i];
    //int rr = a[now].r
  ++tot;
  val[tot]=i;
    if(x!=y)
    {
     split(x,y);
     if (x!=findroot(y))
     {
      link(x,tot);
      //cout<<1<<endl;
      link(y,tot);
  }
  else
  {
   int nnow = mnpos[y];
   cut(xx[nnow-n],nnow);
   cut(yy[nnow-n],nnow);
   link(x,tot);
   link(y,tot);
  }
  }
  while (now<=k && a[now].r<=i)
  {
    if (a[now].a==a[now].b) ans[a[now].id]=1;
    else 
    {
      split(a[now].a,a[now].b);
     if (a[now].a==findroot(a[now].b))
   {
    // cout<<a[now].a<<" "<<a[now].b<<" "<<mn[a[now].b]<<endl;
     if (mn[a[now].b]>=a[now].l) ans[a[now].id]=1;
   }
   }
   now++;
   }
 // cout<<findroot(1)<<" "<<findroot(3)<<endl;
  }
  for (int i=1;i<=k;i++)
  {
    if (ans[i])
    {
     cout<<"ye5\n"; 
  }
  else cout<<"n0\n";
  }
  return 0;
}