タイトル
\(〜\)
BZOJ 5415
LUOGU 4768
その長いタイトルは、我慢する必要はありません。。
分析
二つの小さな感情:
- 私は、いくつかの大物は、この質問を聞いたので\(銅\にAgの\に)ために、\(SPFA \) 、そう、マップの否定的側面を経験していない後、または使用\(ダイクストラ\)それ。
- \(クラスカル\)ツリーは実際にそれの稀な知識に属するとみなされ、再構成\(BZOJ \)のみに(ネットワーク\)\ので、本当に真剣に学習アルゴリズムを、このアルゴリズムと呼ばれ、この時、ブラシタイトル金額は何かを表しています。
公式ソリューション:
この質問は、使用することです\(クラスカル\)ツリーの再構成を、なぜ?自然が決まります。\(クラスカル\)ツリーは、以下の良好な特性を持って再構築します:
- エッジ以外のツリーのリーフノード点は、元のスパニングツリーに対応し、リーフノードは、元のスパニングツリー上のノードです。
- 注文の新しいポイントと作成ので、右の上に元のスパニングツリーのサイズ(リーフノードを除く)ルートノードへの各点からそれを見つけることができるの周りを、ポイントが単調であるアクセスするために、右を指します。
- ため\(クラスカル\)アルゴリズム本質的に貪欲であり、二点\(X \)と\(Y \)\(LCA \)その右を指し、最小スパニングツリーボトルネックに対応します。
- 実際には、このツリーは、バイナリヒープです。
この質問は、構築するためにどのようにしている\(クラスカル\)ツリーの再構成を?
最短の長さは、その後、自分自身を取得するためにこれを使用し、高度を左、アップケリ、建設降順た側の最初のキーの上昇を\(クラスカル\)再構成ツリー。
各サブツリーのために、クエリがその後、サブツリーのルートの水線より下である場合、ツリー内のすべてのサブツリーのリーフノードが通信である場合。他のサブツリーに、必要に応じてその風雲サブツリー出発点、点が費やす必要はありません。
現在の問い合わせのために、我々は、ルートノードをサブツリー見つかったと仮定する\(X- \) (満足(D [X]> P \を \) と\(D [FA [X] <= P \) と開始点(\をY \)サブツリー内の)、時間から\(Y \)リーフノードのいずれかのサブツリーへの直接アクセスを逸脱。
だから我々は、最小を過ごすために1ポイントから番号を選択する必要があるので、これは、リーフノードの数から使用します\(ダイクストラ\)最小との契約は、良いポイントにすべてのポイントを過ごす、この質問にも、完成です。
過去への完全なアイデア、ご参照くださいldxcaicai、笑のを:
その後、ストロークのアイデアを撫で。
- 私たちは、最初に直接ポイント・ツー・ポイント1あたりの最小コストを必要と\(Dijsktra + \)最短の前処理。
- 次いで、構築する(クラスカル\)\のツリーの再構成、及びこのツリー簡単の構築完了した後、部分木の最小コスト1点の距離のルートノードとして、各時点で維持\を(DFSは\)を取得します。
- 最後のポイントは、見つける方法です\(X- \)乗算アルゴリズム:、我々は重要なアルゴリズムのデビューをします。ダイレクトプラスポイント右\(>のp \)を掛けることができます木に制限されています。
コード
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxn=4e5+10,maxm=8e5+10,inf=0x3f3f3f3f;
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++='\n';
}
int vc[maxm<<1],Nc[maxm<<1],hc[maxn<<1],lc;
inline void addc(int x,int y)
{
vc[++lc]=y,Nc[lc]=hc[x],hc[x]=lc;
}
struct Orz{int x,y,l,a;}e[maxm],p[maxn<<1];
inline bool cmp(Orz c,Orz d)
{
return c.a>d.a;
}
int fa[maxn<<1];
inline int get(int x)
{
return fa[x]==x?x:fa[x]=get(fa[x]);
}
int n,m,cnt,sum;
inline void Kruskal()
{
cnt=n,sum=0;
for (int i=1; i<=(n<<1); ++i) fa[i]=i;
sort(e+1,e+m+1,cmp);
for (int i=1; i<=m; ++i)
{
int x=get(e[i].x),y=get(e[i].y);
if (x==y) continue;
addc(++cnt,x),addc(cnt,y);
fa[x]=fa[y]=cnt;
p[cnt].a=e[i].a;
if (++sum==n-1) break;
}
}
int ver[maxm],edge[maxm],Next[maxm],head[maxn],len;
inline void add(int x,int y,int z)
{
ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
ver[++len]=x,edge[len]=z,Next[len]=head[y],head[y]=len;
}
int dist[maxn];
bool vis[maxn];
inline void Dijkstra(int s)
{
memset(dist,0x3f,sizeof(dist));
memset(vis,0,sizeof(vis));
priority_queue<pii,vector<pii>,greater<pii> >q;
q.push(make_pair(0,s)),dist[s]=0;
while (!q.empty())
{
int x=q.top().second;
q.pop();
if (vis[x]) continue;
vis[x]=1;
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i],z=edge[i];
if (dist[y]>dist[x]+z)
{
dist[y]=dist[x]+z;
q.push(make_pair(dist[y],y));
}
}
}
for (int i=1; i<=n; ++i) p[i].l=dist[i];
}
int f[maxn][20],d[maxn];
inline void dfs(int x,int pa)
{
d[x]=d[pa]+1,f[x][0]=pa;
for (int i=1; i<=19; ++i) f[x][i]=f[f[x][i-1]][i-1];
for (int i=hc[x]; i; i=Nc[i])
{
int y=vc[i];
dfs(y,x);
p[x].l=min(p[x].l,p[y].l);
}
}
inline int query(int x,int y)
{
for (int i=19; i>=0; --i)
if (d[x]-(1<<i)>0 && p[f[x][i]].a>y) x=f[x][i];
return p[x].l;
}
inline void Clear()
{
memset(f,0,sizeof(f));
memset(d,0,sizeof(d));
memset(head,0,sizeof(head));
memset(hc,0,sizeof(hc));
len=lc=0;
}
int main()
{
int T;read(T);
while (T--)
{
Clear();
read(n);read(m);
for (int i=1; i<=m; ++i) read(e[i].x),read(e[i].y),read(e[i].l),read(e[i].a),add(e[i].x,e[i].y,e[i].l);
for (int i=n+1; i<=(n<<1); ++i) p[i].l=inf;
Dijkstra(1);
int Q,K,S;
read(Q);read(K);read(S);
Kruskal();
dfs(cnt,0);
int lastans=0;
while (Q--)
{
int v,p;read(v);read(p);
int x=(v+lastans*K-1)%n+1,y=(p+lastans*K)%(S+1);
write(lastans=query(x,y));
}
}
flush();
return 0;
}