Contest:https://www.jisuanke.com/contest/3004?view=challenges
爲什麼感覺好寫的題這麼少呢。。
A. The beautiful values of the palace(規律+二維偏序問題)
題目鏈接:https://nanti.jisuanke.com/t/41298
題目大意:有一個n*n的宮殿,蛇形序列,每個點都有自己的價值。只有m個點有真實值。p次查詢。對於每次查詢,找到裏面所有值的數位之和。
思路:首先要有一個映射關係,即將(x,y)對應的真實值求出。經過觀察我們容易發現規律,洛谷上有一個螺旋矩陣的題,換過來就好了:https://www.luogu.org/problem/P2239。然後就是計算答案了。
離線處理,很容易發現就是一個二位偏序問題。
對詢問點和有效點進行排序,枚舉右端點,是一個宮殿就更新線段樹,否則查詢。
ACCode:
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=1e5+10;
const int MAXM=1e6+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
struct SegTree{
struct Node{
int l,r,len;
ll Sum;
};
Node Tree[MAXM<<2];
void PushUp(int rt){
Tree[rt].Sum=Tree[rt<<1].Sum+Tree[rt<<1|1].Sum;
}
void Build(int l,int r,int rt){
Tree[rt].l=l;Tree[rt].r=r;
Tree[rt].Sum=0;
if(l==r) return ;
int mid=(l+r)>>1;
Build(l,mid,rt<<1);Build(mid+1,r,rt<<1|1);
}
void Update(int pos,ll val,int rt){
if(pos==0) return ;
if(Tree[rt].l==Tree[rt].r){
Tree[rt].Sum+=val;
return ;
}
if(pos<=Tree[rt<<1].r) Update(pos,val,rt<<1);
else Update(pos,val,rt<<1|1);
PushUp(rt);
}
ll Query(int ql,int qr,int rt){
if(ql>qr) return 0;
if(ql<=Tree[rt].l&&Tree[rt].r<=qr) return Tree[rt].Sum;
if(qr<=Tree[rt<<1].r) return Query(ql,qr,rt<<1);
else if(ql>=Tree[rt<<1|1].l) return Query(ql,qr,rt<<1|1);
else return 1ll*Query(ql,qr,rt<<1)+Query(ql,qr,rt<<1|1);
}
void Show(int rt){
printf("l=%d r=%d Sum=%lld\n",Tree[rt].l,Tree[rt].r,Tree[rt].Sum);
if(Tree[rt].l==Tree[rt].r) return ;
Show(rt<<1);Show(rt<<1|1);
}
};
struct Point{
int i,j,val,opt;
friend int operator < (Point a,Point b){
if(a.i!=b.i) return a.i<b.i;
if(a.j!=b.j) return a.j<b.j;
return a.opt<b.opt;
}
};
SegTree Seg;
Point Dots[MAXN],Suf[MAXM];
PII Ask[MAXN][2];
ll Ans[MAXM];
map<PII,int> MP;
ll GetVal(int n,int i,int j){
ll ans;
ll mi=min(i,min(j,min(n-i+1,n-j+1)));
if(i<=j) ans=1ll*mi*(1ll*4*(n-1)-4*mi)+1ll*10*mi-4*n-3+i+j;
else ans=1ll*mi*(4*n-4*mi)+1ll*2*mi+1-i-j;//模擬過程
return ans;
}
ll Work(int n,int i,int j){
ll x=GetVal(n,n+1-i,n+1-j),ans=0;
while(x){
ans+=x%10;
x/=10;
}return ans;
}
int main(){
int T;scanf("%d",&T);
while(T--){
MP.clear();
int n,m,q;scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;++i){
int x,y;scanf("%d%d",&x,&y);
Dots[i].i=x;Dots[i].j=y;Dots[i].val=Work(n,x,y);
}
for(int i=1;i<=q;++i){
int x1,x2,y1,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
Ask[i][0]=make_pair(x1,y1);Ask[i][1]=make_pair(x2,y2);
}
Seg.Build(1,MAXM,1);
int sum=m+4*q;
for(int i=1;i<=m;++i){//共m個有效點
int x=Dots[i].i,y=Dots[i].j;
Suf[i].i=x;Suf[i].j=y;Suf[i].val=Dots[i].val;Suf[i].opt=1;
}
for(int i=1;i<=q;++i){//共q個詢問點
Suf[i+m].i=Ask[i][0].first-1;Suf[i+m].j=Ask[i][0].second-1;Suf[i+m].opt=2;
Suf[i+m+q].i=Ask[i][0].first-1;Suf[i+m+q].j=Ask[i][1].second;Suf[i+m+q].opt=2;
Suf[i+m+2*q].i=Ask[i][1].first;Suf[i+m+2*q].j=Ask[i][0].second-1;Suf[i+m+2*q].opt=2;
Suf[i+m+3*q].i=Ask[i][1].first;Suf[i+m+3*q].j=Ask[i][1].second;Suf[i+m+3*q].opt=2;
}sort(Suf+1,Suf+sum+1);//將詢問點排序
// for(int i=1;i<=sum;++i) printf("i=%d j=%d val=%lld opt=%d\n",Suf[i].i,Suf[i].j,Suf[i].val,Suf[i].opt);
for(int i=1;i<=sum;++i){
int x=Suf[i].i,y=Suf[i].j,val=Suf[i].val,opt=Suf[i].opt;
if(opt==1){//是一個宮殿
Seg.Update(y,val,1);
}
else{//是一個起點||其他詢問點||終點,刷新答案後不用換
Ans[i]=Seg.Query(1,y,1);
MP[make_pair(x,y)]=i;
// printf("x=%d y=%d Ans=%lld\n",x,y,Ans[MP[make_pair(x,y)]]);
}
}
//Ans=[x2][y2]-[x2][y1-1]-[x1-1][y2]+[x1-1][y1-1];
for(int i=1;i<=q;++i){
PII str=Ask[i][0],ed=Ask[i][1];
ll ans=Ans[MP[make_pair(ed.first,ed.second)]]-Ans[MP[make_pair(ed.first,str.second-1)]]-Ans[MP[make_pair(str.first-1,ed.second)]]+Ans[MP[make_pair(str.first-1,str.second-1)]];
// printf("%lld - %lld - %lld + %lld = %lld\n",Ans[MP[make_pair(ed.first,ed.second)]],Ans[MP[make_pair(ed.first,str.second-1)]],Ans[MP[make_pair(str.first-1,ed.second)]],Ans[MP[make_pair(str.first-1,str.second-1)]],ans);
printf("%lld\n",ans);
}
}
}
B. super_log(歐拉降冪)
題目鏈接:https://nanti.jisuanke.com/t/41299
數論隊友的題:https://blog.csdn.net/henucm/article/details/100290033
F. Greedy Sequence(靜態主席樹)
題目鏈接:https://nanti.jisuanke.com/t/41303
題目大意:給出1個長度爲n的序列A,每個數字都是唯一的&&1<=A[i]<=n
找到n個序列,滿足第i個序列B[1]=i,每個序列單調不增(由於元素唯一,所以也就是單調減)
每次選擇的元素在A數組中的位置相差不能大於k。
找出最大的字典序序列
思路:區間最大的<=B[j-1]的值,明顯的靜態 主席樹
ACCode:
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
struct ChairTree{
int Rt[MAXN<<5],Lc[MAXN<<5],Rc[MAXN<<5],Sum[MAXN<<5];
int NodeCnt;
void Build(int l,int r,int rt){
rt=++NodeCnt;
if(l==r) return ;
int mid=(l+r)>>1;
Build(l,mid,Lc[rt]);Build(mid+1,r,Rc[rt]);
}
int Modify(int pos,int l,int r,int rt){
int Nrt=++NodeCnt;
Lc[Nrt]=Lc[rt];Rc[Nrt]=Rc[rt];Sum[Nrt]=Sum[rt]+1;
if(l==r) return Nrt;
int mid=(l+r)>>1;
if(pos<=mid) Lc[Nrt]=Modify(pos,l,mid,Lc[Nrt]);
if(pos>mid) Rc[Nrt]=Modify(pos,mid+1,r,Rc[Nrt]);
return Nrt;
}
int Query(int ql,int qr,int l,int r,int k){
//[ql,qr]種找最後一個<=k的元素
if(l==r) return l;
int xl=Sum[Lc[qr]]-Sum[Lc[ql]],xr=Sum[Rc[qr]]-Sum[Rc[ql]];
int mid=(l+r)>>1;
// printf("xl=%d xr=%d l=%d r=%d mid=%d k=%d\n",xl,xr,l,r,mid,k);
//[l,mid]中存在這樣的元素
int ans=INF32;
if(mid>=k){//只會出現在[l,mid]
if(xl) ans=Query(Lc[ql],Lc[qr],l,mid,k);
else return ans;
}
else{// mid<k
//[l,mid]和[mid+1,r]都可能出現
if(xr) ans=Query(Rc[ql],Rc[qr],mid+1,r,k);
if(ans!=INF32) return ans;
if(xl) ans=Query(Lc[ql],Lc[qr],l,mid,k);
return ans;
}
}
void Intt(int l,int r){
NodeCnt=0;
Build(l,r,Rt[0]);
}
void Update(int pos,int l,int r,int i){
Rt[i]=Modify(pos,l,r,Rt[i-1]);
}
int Ans(int ql,int qr,int l,int r,int k){//查找最大的<=r的元素
return Query(Rt[ql-1],Rt[qr],l,r,k);
}
};
ChairTree CT;
int A[MAXN],Vis[MAXN];
int Ans[MAXN];
int n,k;
void DFS(int pos){
int val=A[pos];
if(Ans[val]) return ;
int mi=max(1,pos-k),mx=min(n,pos+k);//查詢[mi,mx]的最大的<A[pos]元素
// printf("pos=%d val=%d [%d,%d] \n",pos,val,mi,mx);
int res;
if(val==1) res=INF32;
else res=CT.Ans(mi,mx,1,n,A[pos]-1);
// printf("res=%d\n",res);
if(res==INF32){
Ans[val]=1;//當前沒有更小的了
// printf("Ans[%d]=%d\n",val,Ans[val]);
}
else{
DFS(Vis[res]);//更新更小的
Ans[val]=Ans[res]+1;//resi是可以選擇的元素
// printf("Ans[%d]=%d\n",val,Ans[val]);
}
}
int main(){
int T;scanf("%d",&T);
while(T--){
clean(Ans,0);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i){
scanf("%d",&A[i]);
Vis[A[i]]=i;
}CT.Intt(1,n);
for(int i=1;i<=n;++i) CT.Update(A[i],1,n,i);
for(int i=1;i<=n;++i) DFS(i);
printf("%d",Ans[1]);
for(int i=2;i<=n;++i) printf(" %d",Ans[i]);printf("\n");
}
}
H. Holy Grail(最短路籤到)
題目鏈接:https://nanti.jisuanke.com/t/41305
題目大意:給出n個點,m條邊的有向圖,有負邊權但沒有負權迴路,向圖中添加6條邊,每次添加邊的時候都要保證不會構成負環。輸入添加邊的最小邊權。
思路:添加的最小邊權就是t->s 的最短路,因爲如果添加之後,出現了負環,說明t->s之前存在一條更短的路線。所以必定是t->s的最短路。
ACCode:
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=5e2+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
struct Edge1{
ll v,val,nxt;
Edge1(ll _v=0,ll _val=0,ll _nxt=0){
v=_v;val=_val;nxt=_nxt;
}
};
Edge1 Edge[MAXN<<2];
int Head[MAXN],Ecnt;
ll Dis[MAXN];
int n,m;
void AddEdge(int u,int v,int val){
Edge[Ecnt]=Edge1(v,val,Head[u]);
Head[u]=Ecnt++;
}
void Dijkstra(int str){
clean(Dis,INF64);Dis[str]=0;
priority_queue<PLL,vector<PLL>,greater<PLL> > que;que.push(make_pair(0,str));
while(que.size()){
PLL u=que.top();que.pop();
if(Dis[u.second]<u.first) continue ;
for(int i=Head[u.second];i+1;i=Edge[i].nxt){
int v=Edge[i].v;
if(Dis[v]>Dis[u.second]+Edge[i].val){
Dis[v]=Dis[u.second]+Edge[i].val;
que.push(make_pair(Dis[v],v));
}
}
}
}
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
clean(Head,-1);Ecnt=0;
for(int i=1;i<=m;++i){
ll u,v,val;scanf("%lld%lld%lld",&u,&v,&val);
AddEdge(u,v,val);
}
for(int i=1;i<=6;++i){
int s,t;scanf("%d%d",&s,&t);
Dijkstra(t);
ll ans=Dis[s];ans=-ans;
AddEdge(s,t,ans);
printf("%lld\n",ans);
}
}
}