2024-04-18

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的区间数量)

没时间写了,改天再说吧(应该挺好写的)

posted @ 2024-04-18 21:47  OrangeStar*  阅读(8)  评论(0编辑  收藏  举报