自然Contest14:インターバルカバレッジ+ Tarjan(
A
二乗距離の式の両辺に
長い長いへの注意
コード
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std;
int x[100001];
int y[100001];
int n,i,j,k,l,X,Y,R,ans;
int main()
{
// freopen("a.in","r",stdin);
scanf("%d%d%d%d",&n,&X,&Y,&R);
fo(i,1,n)
scanf("%d%d",&x[i],&y[i]);
fo(i,1,n)
if (((long long)(x[i]-X)*(x[i]-X)+(long long)(y[i]-Y)*(y[i]-Y))<=(long long)R*R)
++ans;
printf("%d\n",ans);
}
B
明らかに、pとkは、ほとんどの脇2の位置であります
位置を考えてみましょうiとn個(左/右/左)
コード
醜い比較
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
using namespace std;
char a[1000001];
int T,n,i,j,k,l,ans,s1,s2,s3,s4;
char ch;
int main()
{
// freopen("b.in","r",stdin);
scanf("%d",&T);
for (;T;--T)
{
ans=-1;
scanf("%d",&n);
fo(i,1,n)
{
ch=getchar();
while (ch<'a' || ch>'z')
ch=getchar();
a[i]=ch;
}
fo(i,1,n)
if (a[i]=='p')
break;
fd(j,n,1)
if (a[j]=='k')
break;
fo(k,i+1,n)
if (a[k]=='i')
break;
fo(l,k+1,n)
if (a[l]=='n')
break;
if (i>=1 && i<k && k<l && l<j && j<=n && a[i]=='p' && a[k]=='i' && a[l]=='n' && a[j]=='k')
ans=max(ans,max(max(k-i-1,l-k-1),j-l-1));
fd(l,j-1,k+1)
if (a[l]=='n')
break;
if (i>=1 && i<k && k<l && l<j && j<=n && a[i]=='p' && a[k]=='i' && a[l]=='n' && a[j]=='k')
ans=max(ans,max(max(k-i-1,l-k-1),j-l-1));
fd(l,j-1,1)
if (a[l]=='n')
break;
fd(k,l-1,i+1)
if (a[k]=='i')
break;
if (i>=1 && i<k && k<l && l<j && j<=n && a[i]=='p' && a[k]=='i' && a[l]=='n' && a[j]=='k')
ans=max(ans,max(max(k-i-1,l-k-1),j-l-1));
printf("%d\n",ans);
}
}
C
* 1つの区間カバレッジ
私は1つのペアの間隔が唯一の答えたら考えることができることを考え始め
メンテナンスブレークポイント、ブレークポイントの次に溶液= 1(プラス含みます)
一次コーティングの後、外側の一定の間隔、間隔はゼロとなり、境界が1となります
一緒間隔で間隔2 *、一定の外に維持することができ、境界+ 2 ^(I-1)
答え私はブレークポイントの総数-2 ^ iは
コード
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define mod 20050321
using namespace std;
long long p[2001];
int L[2001];
int R[2001];
bool b[2001];
long long sum[2001];
long long Sum[2001];
int n,m,i,j,k,l;
long long ans;
int main()
{
// freopen("c.in","r",stdin);
scanf("%d%d",&n,&m);
p[0]=1;
fo(i,1,m)
{
scanf("%d%d",&L[i],&R[i]);
p[i]=p[i-1]*2%mod;
}
sum[0]=sum[n]=1;
fo(i,1,m)
{
fo(j,0,n) Sum[j]=sum[j];
fo(j,0,L[i]-2) Sum[j]=(Sum[j]+sum[j])%mod;
fo(j,R[i]+1,n) Sum[j]=(Sum[j]+sum[j])%mod;
Sum[L[i]-1]=(Sum[L[i]-1]+p[i-1])%mod;
Sum[R[i]]=(Sum[R[i]]+p[i-1])%mod;
ans=0;
fo(j,0,n)
sum[j]=Sum[j],Sum[j]=0,ans=(ans+sum[j])%mod;
printf("%lld\n",(ans-p[i]+mod)%mod);
}
}
D
* 2インターバルカバレッジ
ルーチンは、演算の結果が何らかの尋問オフラインrを配置する場合は、それぞれの時間が計算され動作して答えを追加尋ねます
二つの端部(左と右括弧)のそれぞれを維持するために、次に4つのブラケットの各追加最大のセクションを追加し、ブラケットの各々は一度だけ削除されます
各プラス中間エンドポイントに相当する間隔は、次いで両側プラス新しいエンドポイント、(上書きされた大きなエネルギーが小さい)削除
各お問い合わせは、残りの重量サフィックスの番号を変更しようとしている*と
セットメンテナンスブラケットを使用すると、切断後の間隔の真ん中を見つけるたびに、あなたの答えフェンウィックツリーを維持します
コード
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <set>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define low(x) (x&-(x))
using namespace std;
struct qs{
int l,r,id;
} q[500001];
struct type{
int x,s,t; //0=right 1=left
bool friend operator < (type a,type b) {return a.x<b.x || a.x==b.x && a.t<b.t;}
};
int a[500001][3];
long long ans[500001];
long long tr[500001];
multiset<type> st;
multiset<type> :: iterator I,J;
int n,m,Q,i,j,k,l;
bool cmp(qs a,qs b)
{
return a.r<b.r;
}
void change(int t,long long s)
{
while (t<=n)
{
tr[t]+=s;
t+=low(t);
}
}
long long find(int t)
{
long long ans=0;
while (t)
{
ans+=tr[t];
t-=low(t);
}
return ans;
}
int main()
{
// freopen("d.in","r",stdin);
scanf("%d%d%d",&n,&m,&Q);
fo(i,1,n)
scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]);
fo(i,1,Q)
scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+Q+1,cmp);
st.insert({0,0,1});
st.insert({m,0,0});
fo(i,1,Q)
{
fo(j,q[i-1].r+1,q[i].r)
{
I=st.lower_bound({a[j][0]-1,0,1});
if (I!=st.begin())
{
--I;
if ((*I).x<a[j][0]-1)
{
k=(*I).s;
st.insert({a[j][0]-1,k,0});
st.insert({a[j][0]-1,k,1});
}
}
I=st.upper_bound({a[j][1],0,0});
if (I!=st.end())
{
if (a[j][1]<(*I).x)
{
k=(*I).s;
st.insert({a[j][1],k,0});
st.insert({a[j][1],k,1});
}
}
I=st.lower_bound({a[j][0]-1,0,1});
J=st.upper_bound({(*I).x,0,1});
while (I!=st.end() && (*I).x<a[j][1])
{
if ((*I).s)
change((*I).s,-(long long)a[(*I).s][2]*((*J).x-(*I).x));
st.erase(I);
J=st.lower_bound({a[j][0]-1,0,1});
st.erase(J);
I=st.lower_bound({a[j][0]-1,0,1});
J=st.upper_bound({(*I).x,0,1});
}
st.insert({a[j][0]-1,j,1});
st.insert({a[j][1],j,0});
change(j,(long long)a[j][2]*(a[j][1]-a[j][0]+1));
}
ans[q[i].id]=find(q[i].r)-find(q[i].l-1);
}
fo(i,1,Q)
printf("%lld\n",ans[i]);
}
E
Tarjan * 1
これは、ほとんどの水Eの簡単な数論その道路のほかにする必要があります
Tarjanユニコム強い還元成分、各点に原点から最小DP右側を維持する、最大の右側、最大差
正当性:最大および最小のパス関連の最大差、別の(大きいまたは小さいか)時間の背中を見つけるために計算されなければなりません
細部へのこだわり、極端な値の場所(自宅、エッジ、新しいポイントを)考えます
コード
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
using namespace std;
int a[500001][3];
int ls[200001];
int A[500001][3];
int Ls[200001];
int dfn[200001];
int low[200001];
int d[200001];
int D[200001];
int mx[200001];
int mn[200001];
bool bz[200001];
int num[200001];
int f[200001][3]; //mn,mx,ans
int n,m,Q,i,j,k,l,len,Len,tot,h,t;
void New(int x,int y,int z)
{
++len;
a[len][0]=y;
a[len][1]=ls[x];
ls[x]=len;
a[len][2]=z;
}
void NEW(int x,int y,int z)
{
++Len;
A[Len][0]=y;
A[Len][1]=Ls[x];
Ls[x]=Len;
A[Len][2]=z;
++D[y];
}
void dfs(int t)
{
int i;
++j;
dfn[t]=j;
low[t]=j;
bz[t]=1;
d[++l]=t;
for (i=ls[t]; i; i=a[i][1])
{
if (!dfn[a[i][0]])
{
dfs(a[i][0]);
low[t]=min(low[t],low[a[i][0]]);
}
else
if (bz[a[i][0]])
low[t]=min(low[t],dfn[a[i][0]]);
}
if (dfn[t]==low[t])
{
++tot;
while (d[l]!=t)
{
bz[d[l]]=0;
num[d[l--]]=tot;
}
bz[d[l]]=0;
num[d[l--]]=tot;
}
}
int main()
{
// freopen("e.in","r",stdin);
// freopen("b.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q);
fo(i,1,m)
{
scanf("%d%d%d",&j,&k,&l);
New(j,k,l);
}
memset(mx,190,sizeof(mx));
memset(mn,60,sizeof(mn));
j=l=0;
dfs(1);
fo(j,1,n)
if (num[j])
{
for (i=ls[j]; i; i=a[i][1])
if (num[a[i][0]])
{
if (num[j]==num[a[i][0]])
{
mx[num[j]]=max(mx[num[j]],a[i][2]);
mn[num[j]]=min(mn[num[j]],a[i][2]);
}
else
NEW(num[j],num[a[i][0]],a[i][2]);
}
}
h=t=0;
fo(i,1,tot)
if (!D[i])
d[++t]=i;
fo(i,1,tot)
{
f[i][0]=mn[i];
f[i][1]=mx[i];
f[i][2]=f[i][1]-f[i][0];
}
while (h<t)
{
for (i=Ls[d[++h]]; i; i=A[i][1])
{
f[A[i][0]][0]=min(f[A[i][0]][0],min(f[d[h]][0],A[i][2]));
f[A[i][0]][1]=max(f[A[i][0]][1],max(f[d[h]][1],A[i][2]));
f[A[i][0]][2]=max(f[A[i][0]][2],A[i][2]-f[d[h]][0]);
f[A[i][0]][2]=max(f[A[i][0]][2],mx[A[i][0]]-f[d[h]][0]);
f[A[i][0]][2]=max(f[A[i][0]][2],mx[A[i][0]]-A[i][2]);
f[A[i][0]][2]=max(f[A[i][0]][2],f[d[h]][1]-A[i][2]);
f[A[i][0]][2]=max(f[A[i][0]][2],f[d[h]][1]-mn[A[i][0]]);
f[A[i][0]][2]=max(f[A[i][0]][2],A[i][2]-mn[A[i][0]]);
f[A[i][0]][2]=max(f[A[i][0]][2],max(f[d[h]][2],0));
--D[A[i][0]];
if (!D[A[i][0]])
d[++t]=A[i][0];
}
}
for (;Q;--Q)
{
scanf("%d",&j);
if (num[j] && f[num[j]][2]>=0)
printf("%d\n",f[num[j]][2]);
else
printf("-1\n");
}
}
F
Tarjan * 2
もちろん、あなたはフェローシップを見つけることができ、その後、木の会長でポイントカット、最適化、さらにはサイドを見つけます
胡口
プレス水平/垂直線順次走査線分の交差及びBを考えます
葉で、Bに間隔bで加入時に見ては、質問器に接続されている場合でも、
それも、いくつかのセグメントを削除していない場合、場合でも、新しい葉ノードリーフノードの元側に尋ねられたとき、各セクションは、彼の息子の側に接続されています
または修飾クエリ演算ノードとエッジの数は、レベルログnを接続しました
両方の注文はカットポイントに求めてTarjan出終わった後、
コード
私は書いていません