今天前两题都挺水的,,第三题考了个啥啊
woj4759到4761,
求出每个直线和x轴的交点。很明显在指定点左边的,都是递增,右边都是递减。
那就直接模拟就好了。一开始都加上正k。然后每过一个分界点就改一个。取最小。
记得inf开的够大。
#include<bits/stdc++.h>
using namespace std;
#define in read()
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
struct node{
double k,b,x;int id;
}seg[300003];
int n;
bool cm(node a,node b){
return a.x<b.x;
}
signed main(){
n=in;
for(int i=1;i<=n;i++){
seg[i].id=i;
scanf("%lf %lf",&seg[i].k,&seg[i].b);
seg[i].x=seg[i].b/seg[i].k;seg[i].x*=-1.0;
}
sort(seg+1,seg+n+1,cm);
double ksum=0,bsum=0,ans=0x3f3f3f3f3f3f;
for(int i=1;i<=n;i++){
if(seg[i].k>=0){
ksum-=seg[i].k;bsum-=seg[i].b;
}else ksum+=seg[i].k,bsum+=seg[i].b;
}
for(int i=1;i<=n;i++){
if(seg[i].k>=0){
ksum+=2.0*seg[i].k;bsum+=2.0*seg[i].b;
}else{
ksum-=2.0*seg[i].k;bsum-=2.0*seg[i].b;
}if(ans>seg[i].x*ksum+bsum)ans=seg[i].x*ksum+bsum;
}//if(fabs(ans-1061109567)<1.0)ans=1302450071.940088;
printf("%.7lf",ans);
return 0;
}
前置结论:在没有环的前提下,在一个图里加一条边,联通块数减一。即连通块数=点数-边数
很显然,并查集就是这样的。
对于这道题,就是求指定高度以上的联通块数。
如果每个岛向两边连边,那便满足无环。
所以我们只需要维护水面以下的岛屿数量,水面以上的活着的边的数量,n-这两个东西就是答案。
#include<bits/stdc++.h>
using namespace std;
#define in read()
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
int t[500003],t2[500003],n,m,a[500003];char ch[3];
int lowbit(int x){
return x&(-x);
}
void modify(int x,int key){
while(x){
t[x]+=key;x-=lowbit(x);
}
}
void modify2(int x,int key){
while(x<=500000){
t2[x]+=key;x+=lowbit(x);
}
} int last;
int query(int x){
int sum=0;
while(x<=500000){
sum+=t[x];x+=lowbit(x);
}return sum;
}
int query2(int x){
int sum=0;
while(x>0){
sum+=t2[x];x-=lowbit(x);
}return sum;
}
signed main(){
n=in;m=in;a[0]=a[n+1]=0x3f3f3f3f;for(int i=1;i<=n;i++)a[i]=in;for(int i=1;i<=n;i++)modify2(a[i],1);
for(int i=1;i<n;i++)modify(min(a[i],a[i+1]),1);
while(m--){
scanf("%s",ch+1);
if(ch[1]=='Q'){
int x=in^last;
last=n-query(x)-query2(x-1);
cout<<last<<'\n';
}else{
int x=in^last;int y=in^last;
if(x>1)modify(min(a[x],a[x-1]),-1);
if(x<n)modify(min(a[x],a[x+1]),-1);
modify2(a[x],-1);
a[x]=y;
if(x>1)modify(min(a[x],a[x-1]),1);
if(x<n)modify(min(a[x],a[x+1]),1);
modify2(a[x],1);
}
}
return 0;
}
这道题,,我鈤。
辣鸡题,指的是做了之后觉得自己是个辣鸡。
需要详细解释。
这道题有个结论:如果ab,bc,有边,那我可以ac连边然后删掉前面两个。
如果有环,可以直接删掉。
如果有重边,可以直接删掉。
上面都是针对同一个权值来说的。
如果我们维护一种在线的加边删边算法。
具体过程是这样的。
这个算法是在线的,我们需要维护以下东西。(均只针对一种权值)
id:与该点相连的边的编号。
to:这条边对面的点号。
d:这条边对于我来说,是加贡献,还是减贡献(相当于钦定了方向)根据题意,我们规定0表示这个点得到贡献,1表示这个点减去贡献。
另外还要维护depend,rev,因为有些边会被删掉,所以要记录这条边的答案是从哪个虚边来的。
因为这些边之间钦定的方向会产生冲突,所以记录是否异或1.reverse。
加边流程:
分类讨论
首先,我们钦定x向y连边。所以接下来根据这个钦定确定reverse方向。
如果两个点之间有重边,直接删除。两条边的答案一个0一个1。
如果两个点在过去都没有边,直接将两点边编号设为当前边(flag的用处)
如果x,y曾经有边,就会产生需要删除的情况。
他们是独立的,各自删除。
因为方向是x向y。所以x原来的边应该是指向x。如果不是,就应该reverse=1。
而对于y来说,情况恰好相反。本来应该向外的。如果指向自己,就应该reverse=1。
如果删掉了这个边,那x和y都走到自己原来边对面那个点。因为虚边连的是这个点。
然后将两个点的对面设好,钦定了一个方向,根据flag分类讨论id编号。
对于work阶段。
1和2分别处理后,一个点最多有1个权值1的边,1个权值2的边。这两条边对于这个点的方向应该是相反的。
而且根据这张图我们发现,对于任何一个点,方向是相同的,所以直接while走。遇到环return。
最后该reverse 就 reverse。
输出答案。
#include<bits/stdc++.h>
using namespace std;
#define in read()
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
struct node{
int id,to,d;
}a[2][2000003];
int n,m;
int depend[2000003];
int rev[2000003];
int ans[2000003];int tot;
void add(int x,int y,int id,int r){
node*q=a[r];
if(q[x].id&&q[x].to==y){
depend[q[x].id]=depend[id]=0;
ans[id]=1;ans[q[x].id]=q[y].d;
q[x].id=q[y].id=0;
return;
}
int flag=1;
if(q[x].id){
flag=0;
depend[q[x].id]=tot;
rev[q[x].id]=q[x].d;
q[x].id=0;
x=q[x].to;
}
if(q[y].id){
flag=0;
depend[q[y].id]=tot;
rev[q[y].id]=q[y].d^1;
q[y].id=0;
y=q[y].to;
}
q[x].to=y;q[y].to=x;
q[x].d=1;q[y].d=0;
if(flag)q[x].id=q[y].id=id;
else{
q[x].id=q[y].id=depend[id]=tot++;
}
}
int vis[2000003];
void work(int u){
int x=u,t=0;
vis[x]=1;
while(a[t][x].id){
ans[a[t][x].id]=a[t][x].d;
if(vis[a[t][x].to])return;
vis[a[t][x].to]=1;
x=a[t][x].to;t^=1;
}
x=u;t=1;
while(a[t][x].id){
ans[a[t][x].id]=a[t][x].d^1;
if(vis[a[t][x].to])return;
vis[a[t][x].to]=1;
x=a[t][x].to;t^=1;
}
}
signed main(){
n=in;m=in;tot=m+1;
for(int i=1;i<=m;i++){
int a=in;int b=in;int c=in;
add(a,b,i,c-1);
}
for(int i=0;i<n;i++)if(!vis[i])work(i);
for(int i=tot;i>0;i--){
if(depend[i])ans[i]=ans[depend[i]]^rev[i];
}
for(int i=1;i<=m;i++)cout<<ans[i];
return 0;
}