問題A:文字列
制限時間:5000ミリ秒のメモリ制限:256メガバイト
説明
長さSの列とnの長さである所定のm個のT列は愛= S1S2 ... SiT1T2 ... TMSI + 1SI + 2 ... SN定義しました
ストリングS I = nはTの前に文字列を表す場合、I = 0は、文字列の前にTストリングSを示す場合
クエリL、R、K、X、Yのために、辞書式に最小のあい、もし辞書式に最小Iの複数の最小出力条件を満たすために出力がある場合、I -1式I満たすl≤を見つけます。 i≤rとx≤(I MOD K)≤y。
入力
入力文字列と文字列S Tと整数qの最初の行は、Qは、クエリを表します
各質問総行番号5 L、R、K、X、Y用
出力
ラインqの合計数、qは答えを表します
Sample Input
abc d 4
0 3 2 0 0
0 3 1 0 0
1 2 1 0 0
0 1 3 2 2
Sample Output
2 3 2 -1
ヒント
データ1≤nの30%、M、q≤10^ 3
100%にデータ1≤n、M、q≤10^ 5
溶液
それを書き留めていません。。。LCPは、おそらくクエリー配列と、サブブロックの最初の行であります
もっと吐き気を達成するためのコード、それを言うための時間。
問題B:MEX
制限時間:1000msのメモリ制限:512メガバイト
説明
あなたの無限の配列、初期の時間を与える3つの動作モードがあり、ゼロです。
図1に示すように、[L、R]が1に設定されている動作間隔に与えられます
図2に示すように、[L、R]が0に設定されている動作間隔に与えられます
操作3与えられた区間[L、R] 0,1が逆。
n個の操作の合計、各最小位置の後に0を出力する動作。
入力
最初の行の整数N、ある動作を表します
次のn行、各ライン三つの整数オペアンプ、L、Rは、動作を表します
出力
n行の合計は、1つの行が整数回答を表します
Sample Input
3
1 3 4
3 1 6
2 1 3
Sample Output
1
3
1
ヒント
データ1≤n≤10の30%^3,1≤l≤r≤10^ 18
100%にデータ1≤n≤10^ ^5,1≤l≤r≤1018
溶液
LとR、その後個別のオフラインを生き残る、データ範囲を参照してください
2つの部分は質問を表現することができるように、ミドルL、R、R + 1、三つに離散化座標することを忘れません
最小位置L、0は、セグメントツリーで発生間隔におけるRを維持検討
次に、2本のツリーラインを構築し、完全な初期化は、完全な1 0であります
2一緒に直接変更する場合、全ての平準化、反転ノードの双方が十分に交換する場合など。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF 1000000000000000001
struct node{
int l,r;
int pos;
int tag;
}t[2000001];
int cnt;
int root[2];
int siz;
void build(int &o,int l,int r,bool mark){
if(!o)o=++cnt;
t[o].tag=-1;
if(l==r){
if(mark)t[o].pos=l;
else t[o].pos=siz+1;
return;
}
int mid=(l+r)/2;
build(t[o].l,l,mid,mark);
build(t[o].r,mid+1,r,mark);
t[o].pos=min(t[t[o].l].pos,t[t[o].r].pos);
}
void pushdown(int o,int l,int r){
int ls=t[o].l,rs=t[o].r;
if(t[o].tag==-1)return;
t[ls].tag=t[rs].tag=t[o].tag;
if(t[o].tag==0){
t[ls].pos=t[rs].pos=siz+1;
}
else {
t[ls].pos=l;
t[rs].pos=(l+r)/2+1;
}
t[o].tag=-1;
}
void update(int o1,int o2,int l,int r,int L,int R){
//cout<<o1<<" "<<o2<<endl;
if(L<=l&&r<=R){
t[o1].pos=siz+1;
t[o2].pos=l;
//cout<<l<<endl;
t[o1].tag=0;
t[o2].tag=1;
return;
}
pushdown(o1,l,r);
pushdown(o2,l,r);
int mid=(l+r)/2;
if(L<=mid)update(t[o1].l,t[o2].l,l,mid,L,R);
if(R>mid)update(t[o1].r,t[o2].r,mid+1,r,L,R);
t[o1].pos=min(t[t[o1].l].pos,t[t[o1].r].pos);
t[o2].pos=min(t[t[o2].l].pos,t[t[o2].r].pos);
//cout<<t[o1].pos<<" "<<t[o2].pos<<endl;
}
void swaps(int &o1,int &o2,int l,int r,int L,int R){
//cout<<o1<<" "<<o2<<endl;
if(L<=l&&r<=R){
swap(o1,o2);
return;
}
pushdown(o1,l,r);
pushdown(o2,l,r);
int mid=(l+r)/2;
if(L<=mid)swaps(t[o1].l,t[o2].l,l,mid,L,R);
if(R>mid)swaps(t[o1].r,t[o2].r,mid+1,r,L,R);
t[o1].pos=min(t[t[o1].l].pos,t[t[o1].r].pos);
t[o2].pos=min(t[t[o2].l].pos,t[t[o2].r].pos);
}
int query(int x){
return t[root[x]].pos;
}
struct que{
int opt;
int l,r;
}p[400001],q[400001];
int lis[400001];
int tot;
int minx=-1;
int pos[400001];
signed main(){
int n;
scanf("%lld",&n);
for(int i=1;i<=n;++i){
scanf("%lld%lld%lld",&p[i].opt,&p[i].l,&p[i].r);
lis[++tot]=p[i].l;
lis[++tot]=p[i].r;
lis[++tot]=p[i].r+1;
if(minx==-1)minx=min(p[i].l,p[i].r);
else minx=min(minx,min(p[i].l,p[i].r));
}
sort(lis+1,lis+1+tot);
siz=unique(lis+1,lis+1+tot)-lis-1;
//cout<<siz<<endl;
for(int i=1;i<=siz;++i)pos[i]=lis[i];
pos[siz+1]=INF;
for(int i=1;i<=n;++i){
q[i].opt=p[i].opt;
q[i].l=(lower_bound(lis+1,lis+1+siz,p[i].l))-lis;
q[i].r=(lower_bound(lis+1,lis+1+siz,p[i].r))-lis;
//cout<<q[i].opt<<" "<<q[i].l<<" "<<q[i].r<<endl;
}
build(root[0],1,siz,true);
build(root[1],1,siz,false);
//cout<<cnt<<endl;
for(int i=1;i<=n;++i){
if(minx>1){
puts("1");
continue;
}
if(q[i].opt==1){
update(root[0],root[1],1,siz,q[i].l,q[i].r);
}
if(q[i].opt==2){
update(root[1],root[0],1,siz,q[i].l,q[i].r);
}
if(q[i].opt==3){
swaps(root[0],root[1],1,siz,q[i].l,q[i].r);
}
printf("%lld\n",pos[query(0)]);
}
}
問題C:MST
制限時間:2000ミリ秒のメモリ制限:256メガバイト
説明
点nを与えられ、mはない自己ループ端ことを保証するために接続されたグラフ、及び重量縁。各エッジに対して全てこのような連結グラフの最小スパニングツリーの上端ことは、最大の優先度値を取ることができ、同じ重量の反対側の場合に、得られます。最大重量が無限大の場合、出力1。
入力
二つの整数の最初の行は、n、mは、mは、n個の点のエッジを表します
三つの整数のX、Y、Zの次のMラインは、Zは、ノードXとノードYとの間にあり、長辺の1つを表します
出力
m個の整数出力線、各エッジが回答を表します
Sample Input
4 4
1 2 2
2 3 2
3 4 2
4 1 3
Sample Output
2 2 2 1
ヒント
データ1≤n≤10^3,1≤m≤3* 10 ^ 3の30%
100%のデータ1≤nに、m≤2* 10 ^5,1≤z≤10^ 9
溶液
私たちは、最初の最小スパニングツリーうち建て。
次いで、最小スパニングツリー(x、y)の外側のエッジに対して、最小スパニングツリーX〜Yのパスで最大片側を見つけます。その上に-1の最大値に、最小スパニングツリーの上に常に右側のこの端をそれを作るために、
同様に、(X、Y、LCA)forループ、最小スパニングツリーのエッジの値は、(x、y)は少なくとも重量であるべき-1。次いで、最小スパニングツリーの端に連続次に答えが最小値である-1、(x、y)の最小値をとります。
これら二つのことは明白です。
その後、我々はあなたが何ができるかを掛けます。
#include<bits/stdc++.h>
using namespace std;
struct qwq{
int u,v;
int w;
int nxt;
int id;
}edge[1000001],edge1[1000001];
int fa[1000001];
int findfa(int x){
return x==fa[x]?x:fa[x]=findfa(fa[x]);
}
bool operator <(qwq a,qwq b){
return a.w<b.w;
}
int n,m;
bool vis[1000001];
void kruskal(){
sort(edge1+1,edge1+1+m);
for(int i=1;i<=n;++i)fa[i]=i;
int tmp=0;
for(int i=1;i<=m;++i){
int u=edge1[i].u,v=edge1[i].v;
int x=findfa(u),y=findfa(v);
if(x!=y){
vis[i]=true;
fa[y]=x;
tmp++;
}
if(tmp==n-1)break;
}
}
int cnt=-1;
int head[1000001];
void add(int u,int v,int w,int id){
edge[++cnt].nxt=head[u];
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].id=id;
head[u]=cnt;
}
int re[1000001];
void addedge(){
for(int i=1;i<=m;++i){
int u=edge1[i].u,v=edge1[i].v,w=edge1[i].w,id=edge1[i].id;
if(vis[i]){
add(u,v,w,id);
add(v,u,w,id);
}
}
}
int f[1000001][21];
int maxn[1000001][21];
int dep[1000001];
void dfs(int u,int fa){
for(int i=1;i<=20;++i){
f[u][i]=f[f[u][i-1]][i-1];
maxn[u][i]=max(maxn[u][i-1],maxn[f[u][i-1]][i-1]);
}
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].v,w=edge[i].w,id=edge[i].id;
if(v!=f[u][0]){
re[v]=id;
maxn[v][0]=w;
f[v][0]=u;
dep[v]=dep[u]+1;
dfs(v,u);
}
}
}
int LCA(int x,int y,int &lca){
int ans=0;
if(dep[x]<dep[y])swap(x,y);
int depth=dep[x]-dep[y];
for(int i=0;i<=20;++i){
if(depth&(1<<i)){
ans=max(ans,maxn[x][i]);
x=f[x][i];
}
}
if(x==y){
lca=x;
return ans;
}
for(int i=20;i>=0;--i){
if(f[x][i]==f[y][i])continue;
ans=max(ans,max(maxn[x][i],maxn[y][i]));
x=f[x][i],y=f[y][i];
}
lca=f[x][0];
ans=max(ans,max(maxn[x][0],maxn[y][0]));
return ans;
}
int ans[1000001];
void solve(int x,int u,int w){
x=findfa(x);
while(dep[x]>dep[u]){
ans[re[x]]=max(ans[re[x]],w);
//cout<<re[x]<<endl;
int y=findfa(f[x][0]);
fa[x]=y;
x=findfa(x);
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
scanf("%d%d%d",&edge1[i].u,&edge1[i].v,&edge1[i].w);
edge1[i].id=i;
ans[i]=-1;
}
kruskal();
addedge();
dfs(1,-1);
for(int i=1;i<=n;++i)fa[i]=i;
for(int i=1;i<=m;++i){
int u=edge1[i].u,v=edge1[i].v,w=edge1[i].w;
int id=edge1[i].id;
if(!vis[i]){
int lca;
ans[id]=LCA(u,v,lca)-1;
//cout<<i<<endl;
//cout<<u<<" "<<v<<" "<<lca<<endl;
//cout<<ans[id]<<endl;
solve(u,lca,w-1);
solve(v,lca,w-1);
}
}
for(int i=1;i<=m;++i){
printf("%d ",ans[i]);
}
}