2024-04-18
游戏
集训的时候讲的网络流题
写了一遍就过了都没改,码力见长?
sol:
-
如果没有硬石头就是行和列匹配,每行每列最多匹配一次
-
考虑硬石头,把每行每列由硬石头分成好多块,然后匹配
\(\Large \color{Gold}\downarrow提交记录在这里\)
楼房重建
\(\large{\color{LightBlue}题意}\)
给出 \(n\) 个线段 \((i,0)\) 到 \((i,h_i)\)
求有多少个 \(i\) 满足 \((0,0)\) 到 \((i,h_i)\) 的连线不和其他线段相交
\(\large{\color{LightBlue}解法}\)
不难想到求出每条连线的斜率,斜率比之前选的最后一个的斜率大就选上,小于等于就不选,最后问选了几个
发现左右区间都知道了就可以求当前区间,考虑线段树
每个节点维护 \(a\) 表示答案,\(k\) 表示区间内斜率的最大值
更新的时候
首先左区间能看到的在当前区间一定也可以看到,只需要求右区间中大于左区间最大值的个数
分情况看:
-
如果右区间的最大值小于左区间最大值,返回 \(0\)
-
如果右区间的左区间的最大值小于等于左区间最大值,递归到右区间的右区间
-
否则加上右区间的右区间的答案(必须是右区间的答案减去右区间的左区间的答案,因为右区间的右区间有可能有些被右区间的左区间挡住),递归到右区间的左区间
好绕嘴
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int n,m;
struct Node {
int a;
double k;
}tr[N<<2];
#define ls (u<<1)
#define rs (u<<1|1)
#define mid (lft+rgh>>1)
int query(int u,int lft,int rgh,double val) {
if(tr[u].k<=val) return 0;
if(lft==rgh) return (tr[u].k>val);
if(tr[ls].k<=val) return query(rs,mid+1,rgh,val);
return query(ls,lft,mid,val)+tr[u].a-tr[ls].a;
}
void update(int u,int lft,int rgh,int pos,double val) {
if(lft==rgh) {
tr[u].a=1,tr[u].k=val;
return;
}
if(pos<=mid) update(ls,lft,mid,pos,val);
else update(rs,mid+1,rgh,pos,val);
tr[u].k=max(tr[ls].k,tr[rs].k);
tr[u].a=tr[ls].a+query(rs,mid+1,rgh,tr[ls].k);
}
int main() {
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
scanf("%d%d",&n,&m);
while(m--) {
int x;
double y;
scanf("%d%lf",&x,&y);
update(1,1,n,x,y/(1.0*x));
printf("%d\n",tr[1].a);
}
return 0;
}
下午学了一个小时的吉司机线段树,区间最值操作看明白了,区间历史最值学不会,放弃
排序
\({\color{Orange}题意}\)
区间 升序/降序 排列
最后询问某一位置的数
\({\color{Orange}解法}\)
普通的数列排序需要 \(O(n\log n)\),太慢了
如果是 \(01\) 序列,只需要线段树求出区间 \(0,1\) 的个数,然后分成前后两段覆盖就行了
外面套一层二分
把数列中大于等于 \(mid\) 的看成 \(1\),其他看成 \(0\)
发现如果 \(mid\) 大于最后答案,这样排完之后查询的位置是 \(0\)
否则是 \(1\)
按这个调整左右端点就行了
注意求出来区间内 \(1\) 的个数如果是 \(0\),可能会出现查询区间 \(l>r\) 的情况,会数组越界导致RE,特判一下就行
/*I wanna play Honkai:StarRail!*/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int n,m;
int pos;
int w[N];
struct Modify {
int t,l,r;
}q[N];
int tr[N<<2],tg[N<<2];
#define ls (u<<1)
#define rs (u<<1|1)
void pushup(int u) {
tr[u]=tr[ls]+tr[rs];
}
void pushdown(int u,int lft,int rgh) {
if(tg[u]!=-1) {
int mid=lft+rgh>>1;
tr[ls]=tg[u]*(mid-lft+1),tg[ls]=tg[u];
tr[rs]=tg[u]*(rgh-mid),tg[rs]=tg[u];
tg[u]=-1;
}
}
void update(int u,int lft,int rgh,int l,int r,int x) {
if(lft>=l&&rgh<=r) {
tr[u]=x*(rgh-lft+1);
tg[u]=x;
return;
}
pushdown(u,lft,rgh);
int mid=lft+rgh>>1;
if(l<=mid) update(ls,lft,mid,l,r,x);
if(r>mid) update(rs,mid+1,rgh,l,r,x);
pushup(u);
}
int query(int u,int lft,int rgh,int l,int r) {
if(lft>=l&&rgh<=r) return tr[u];
pushdown(u,lft,rgh);
int mid=lft+rgh>>1,res=0;
if(l<=mid) res+=query(ls,lft,mid,l,r);
if(r>mid) res+=query(rs,mid+1,rgh,l,r);
return res;
}
bool check(int x) {
memset(tr,0,sizeof(tr));
memset(tg,-1,sizeof(tg));
for(int i=1;i<=n;i++) if(w[i]>=x) update(1,1,n,i,i,1);
for(int i=1;i<=m;i++) {
int t=q[i].t,l=q[i].l,r=q[i].r;
int cnt=query(1,1,n,l,r);
if(t==0) {
update(1,1,n,l,r-cnt,0);
if(cnt) update(1,1,n,r-cnt+1,r,1);
}
else {
if(cnt) update(1,1,n,l,l+cnt-1,1);
update(1,1,n,l+cnt,r,0);
}
}
return query(1,1,n,pos,pos);
}
int main() {
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<=m;i++) scanf("%d%d%d",&q[i].t,&q[i].l,&q[i].r);
scanf("%d",&pos);
int lft=1,rgh=n,ans;
while(lft<=rgh) {
int mid=lft+rgh>>1;
if(check(mid)) ans=mid,lft=mid+1;
else rgh=mid-1;
}
printf("%d\n",ans);
return 0;
}
晚上模拟赛
\(\large 赛时\)
\({\color{Red}T1}\)
/*I wanna play HonkaiStarRail!*/
/*I wanna play GenshinInpact!*/
/*I love MiHoYo!!!!!!!!!!!!!*/
#include <bits/stdc++.h>
using namespace std;
const int N=5050;
int n;
char str[N];
int T;
pair<int,int> pos[N];
int main() {
scanf("%s",str);
n=strlen(str);
scanf("%d",&T);
int x=0,y=0;
for(int i=0;i<n;i++) {
if(str[i]=='N') y++;
if(str[i]=='S') y--;
if(str[i]=='E') x++;
if(str[i]=='W') x--;
pos[i]={x,y};
}
if(T==0) {
puts("0 0");
return 0;
}
printf("%d %d\n",(T/n)*x+pos[(T-1)%n].first,(T/n)*y+pos[(T-1)%n].second);
return 0;
}
/*
水题,千万别挂分啊
*/
\({\color{Red}T2}\)
/*I wanna play HonkaiStarRail!*/
/*I wanna play GenshinInpact!*/
/*I love MiHoYo!!!!!!!!!!!!!*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10,M=1e6+10;
int n,m;
ll val[N];
int fa[N];
ll sz[N];
struct Edge {
int u,v;
ll w;
bool operator<(const Edge &t)const {
return w>t.w;
}
}edg[M];
int finder(int x) {
if(x!=fa[x]) fa[x]=finder(fa[x]);
return fa[x];
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&val[i]),fa[i]=i,sz[i]=1ll;
for(int i=1;i<=m;i++) {
int u,v;
scanf("%d%d",&u,&v);
edg[i].u=u,edg[i].v=v;
edg[i].w=min(val[u],val[v]);
}
sort(edg+1,edg+m+1);
ll ans=0;
for(int i=1;i<=m;i++) {
int u=edg[i].u,v=edg[i].v;
ll w=edg[i].w;
int fu=finder(u),fv=finder(v);
if(fu==fv) continue;
else {
ans+=sz[fu]*sz[fv]*w;
fa[fv]=fu;
sz[fu]+=sz[fv];
}
}
printf("%lld\n",ans*2ll);
return 0;
}
/*
之前做过?
不开longlong差点见祖宗
*/
\({\color{Red}T3}\)
/*I wanna play HonkaiStarRail!*/
/*I wanna play GenshinInpact!*/
/*I love MiHoYo!!!!!!!!!!!!!*/
#include <bits/stdc++.h>
using namespace std;
const int N=2024;
int n;
int st[N],ed[N];
bool vis[N];
int ans[N];
int main() {
int Task;
scanf("%d",&Task);
for(int Case=1;Case<=Task;Case++) {
memset(vis,false,sizeof(vis));
scanf("%d",&n);
int cnt=0;
for(int i=1;i<=n;i++) {
int t,p;
scanf("%d%d",&t,&p);
if(t==0) {
cnt++;
st[cnt]=p,ed[cnt]=p+cnt;
ans[cnt]=0;
for(int j=1;j<cnt;j++) {
if(!vis[j]&&st[j]>=st[cnt]&&ed[j]<=ed[cnt]) ans[cnt]++;
}
}
else vis[p]=true;
}
printf("Case #%d:\n",Case);
for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
}
return 0;
}
/*
记得之前想了很久
但是当时好像没想出来
也忘了正解了
二维数点?
主席树咋修改啊,不会
线段树套线段树?
空间不够
打个暴力先
ztx太强了写cdq呢
我不会,摆摆摆
*/
\(\large 赛后\)
得分:\(100+100+30=230\)
我是小丑
第三题树状数组就行了
覆盖的区间数量=(右端点<=r的区间数量)-(左端点<l的区间数量)
没时间写了,改天再说吧(应该挺好写的)
标签:04,int,18,mid,2024,rgh,区间,tg,include From: https://www.cnblogs.com/Orange-Star/p/18142839