6.23 模擬賽
阿新 • • 發佈:2021-06-22
6.23 模擬賽
A 城市建設
題意:給定n個點和m條邊和q個詢問,點有點權,這些邊分別在\(t_i\)時刻出現,求在某時刻所有連通的點對點權之積的和
解:將修改按時間排序,列舉修改,每次合併連通塊,處理答案,實現用並查集就可以
注意答案是所有集合的答案之和,所以在合併的時候要處理整體的答案
最後列舉的時候要按詢問列舉,不然會RE
“我今天就是要把s2oj交爆在這裡!!!”
碼:
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cmath> #include<vector> #include<map> #include<queue> #include<deque> #include<set> #include<stack> #include<bitset> #include<cstring> #define ll long long #define re register using namespace std; const int INF=0x3f3f3f3f,N=200010; int f[N]; ll sum[N]; int n,m,q; ll anss=0,ans[N]; struct query{ int id,pos; }que[N]; struct ch{ int t,x,y; }upd[N]; bool cmp1(ch a,ch b){ return a.t<b.t; } bool cmp2(query a,query b){ return a.pos<b.pos; } int find(int a){ if(f[a]!=a) return f[a]=find(f[a]); return a; } void merge(int a,int b){ re ll x=find(a),y=find(b); if(x==y) return; f[x]=y,anss+=sum[x]*sum[y],sum[y]+=sum[x]; } inline int read(){ int x=0,y=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();} while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x*y; } int main(){ n=read(); m=read(); q=read(); for(re int i=1;i<=n;i++) sum[i]=read(),f[i]=i; for(re int i=1;i<=m;i++){ upd[i].t=read(); upd[i].x=read(); upd[i].y=read(); } for(re int i=1;i<=q;i++) que[i].pos=read(),que[i].id=i; sort(upd+1,upd+1+m,cmp1); sort(que+1,que+1+q,cmp2); int qq=1; int j=1; for(int i=1;i<=q;i++){ for(;(j<=m)&&(upd[j].t<=que[i].pos);j++){ merge(upd[j].x,upd[j].y); } ans[que[i].id]=anss; } for(re int i=1;i<=q;i++) printf("%lld\n",ans[i]); return 0; }
B 矩形2
題意:有n個矩形,所有矩形的其中一條邊在x軸上,求所有矩形所覆蓋到的面積
解:可以用掃描線,但是發現矩形們的其中一條邊都在一條直線上,也就是高度的基準線一樣,我們可以將豎直邊進行排序,掃一遍,用堆來維護當前區間的最大高度,處理出每兩根豎直線之間矩形的面積,實現可用可刪堆
碼:
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cmath> #include<vector> #include<map> #include<queue> #include<deque> #include<set> #include<stack> #include<bitset> #include<cstring> #define ll long long #define pii pair<int,int> using namespace std; const int INF=0x3f3f3f3f,N=100010; int n,pos=0; ll ans=0; struct ss{ ll x; int id,h; bool typ; }op[N]; bool cmp(ss a,ss b){ return (a.x==b.x)?(a.typ?0:1):a.x<b.x; } inline int read(){ int x=0,y=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();} while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x*y; } struct PQ{ priority_queue<int> val,delv; void clear(){priority_queue<int> nv,nd;swap(nv,val);swap(nd,delv);} void pop(int x){delv.push(x);} void push(int x){val.push(x);} int top(){ while(!delv.empty()&&delv.top()==val.top()) delv.pop(),val.pop(); return val.empty()?0:val.top(); } }heap; int main(){ n=read(); for(int i=1;i<=n;i++){ op[2*i-1].x=read(),op[2*i].x=read(),op[2*i-1].h=op[2*i].h=read(); op[2*i-1].typ=0,op[2*i].typ=1; } sort(op+1,op+2*n+1,cmp); heap.clear(); for(int i=1;i<=2*n;i++){ if(i>=2) ans+=(op[i].x-op[i-1].x)*heap.top(); if(!op[i].typ){ pos++; heap.push(op[i].h); }else{ pos--; heap.pop(op[i].h); } } cout<<ans<<endl; return 0; }
C 新型計算機
題意:一個序列,從第一個開始遍歷,讀到幾就再往後讀幾個數,若剛好讀完最後一個數,那麼這個序列就是一個合法序列,現給出一個不合法序列,進行把序列裡每一個數都加上或減去一個數,使之變為合法的,求這個數的絕對值最小是多少
解:可最短路可DP,最短路建圖題,樹狀陣列優化DP,我寫的最短路
碼:
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cmath> #include<vector> #include<map> #include<queue> #include<deque> #include<set> #include<stack> #include<bitset> #include<cstring> #define ll long long #define pii pair<int,int> using namespace std; const int INF=0x3f3f3f3f,N=1000010; int e[4*N],ne[4*N],idx,h[N],w[4*N],n,ls[N],rs[N]; inline int read(){ int x=0,y=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();} while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x*y; } void add(int a,int b,int c){ e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++; } namespace dijkstra{ int dist[N]; bool vis[N]; int dijkstra(int st,int ed){ memset(dist,0x3f,sizeof dist); priority_queue<pii,vector<pii>,greater<pii> > q; dist[st]=0; q.push(make_pair(0,st)); while(q.size()){ pii op=q.top(); q.pop(); int dis=op.first,ver=op.second; if(vis[ver]) continue; vis[ver]=1; for(int i=h[ver];~i;i=ne[i]){ int j=e[i]; if(dist[j]>dist[ver]+w[i]){ dist[j]=dist[ver]+w[i]; q.push(make_pair(dist[j],j)); } } } if(dist[ed]==0x3f) return -1; return dist[ed]; } } int main(){ memset(h,-1,sizeof h); n=read(); for(int i=1,k;i<=n;i++){ k=read(); if(i+k<=n) add(i,i+k+1,0); else add(i,n+1,i+k-n); for(int j=i+1;j<=i+k+1&&j<=n&&!ls[j];j++) ls[j]=1,add(j,j-1,1); for(int j=i+k+1;j<=n&&!rs[j];j++) rs[j]=1,add(j,j+1,1); } ll ans=dijkstra::dijkstra(1,n+1); printf("%lld\n",ans); return 0; }
D 郵箱
簡化版題意:給你倆序列,給你一堆詢問,詢問是倆序列裡的兩段區間,問這兩段區間裡相同數/個數的乘積之和除以
第二段區間長度
解:莫隊搞,和這個一樣,把一個詢問拆成四個詢問,每個詢問都形如 \(get(pos_1,x)\times get(pos_2,x)\) ,然後排序莫隊掃就可以了,還有陣列開小了會有神奇的效果
碼:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define int long long
#define ll long long
using namespace std;
const int INF=0x3f3f3f3f,N=100010;
int n,m,a[N],b[N],q,cnt=0,be[N],op;
int cntl[N],cntr[N],res=0,l,r,ans[10*N];
int ans1[10*N];
struct query{
int ql,qr,id,typ;
query(int l=0,int r=0,int id=0,int typ=0):ql(l),qr(r),id(id),typ(typ){}
}que[40*N];
bool cmp(query a,query b){
return (be[a.ql]==be[b.ql])?a.qr<b.qr:a.ql<b.ql;
}
inline ll read(){
ll x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
void movel(int t){
if(t==1){
l++;
++cntl[a[l]];
res+=cntr[a[l]];
}else{
--cntl[a[l]];
res-=cntr[a[l]];
l--;
}
}
void mover(int t){
if(t==1){
r++;
++cntr[b[r]];
res+=cntl[b[r]];
}else{
--cntr[b[r]];
res-=cntl[b[r]];
r--;
}
}
ll gcd(ll a,ll b){
return b==0ll?a:gcd(b,a%b);
}
signed main(){
n=read();m=read();
op=sqrt(n);
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=m;i++) b[i]=read();
q=read();
for(int i=1;i<=q;i++){
int q1,q2,q3,q4;
q1=read(),q2=read(),q3=read(),q4=read();
que[++cnt]=query(q2,q4,i,1);
que[++cnt]=query(q2,q3-1,i,-1);
que[++cnt]=query(q1-1,q4,i,-1);
que[++cnt]=query(q1-1,q3-1,i,1);
ans1[i]=q4-q3+1;
}
for(int i=1;i<=n;i++) be[i]=i/op+1;
sort(que+1,que+1+cnt,cmp);
for(int i=1;i<=cnt;i++){
while(l>que[i].ql) movel(-1);
while(r<que[i].qr) mover(1);
while(l<que[i].ql) movel(1);
while(r>que[i].qr) mover(-1);
if(que[i].typ==1) ans[que[i].id]+=res;
else ans[que[i].id]-=res;
}
for(int i=1;i<=q;i++){
int g=gcd(ans[i],ans1[i]);
printf("%lld %lld\n",ans[i]/g,ans1[i]/g);
//printf("%d\n",ans[i]);
}
return 0;
}