选拔赛的题解,~~~

题目链接:请点击

A题

素数筛 + 线段树(树状数组)

先用素数筛打表,然后线段树更新,遍历求出值,O(1)查询即可

AC代码:

/*num数组 是把记录 数是否存在 存在即为1。
总共有N个数,如何判断第i+1个数到最后一个
数之间有多少个数小于第i个数呢?不妨假设
有一个区间 [1,N],只需要判断区间[i+1,N]之
间有多少个数小于第i个数。如果我们把总区间初
始化为0,然后把第i个数之前出现过的数都在相应
的区间把它的值定为1,那么问题就转换成了[i+1,N]
值的总和
*/
#include <stdio.h>
#include <bits/stdc++.h>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define size 1000000 + 7
#define min(a, b) a > b ? b : a
typedef long long LL;
#define MAXN 1000005
#define MAXL 1299710
LL prime[MAXN];
LL check[MAXL];
LL PP[MAXL];
void init(){ LL tot = ;
memset(check, , sizeof(check));
for (LL i = ; i < MAXL; ++i)
{
if (!check[i])
{
prime[tot++] = i;
}
for (LL j = ; j < tot; ++j)
{
if (i * prime[j] > MAXL)
{
break;
}
check[i*prime[j]] = prime[j];
if (i % prime[j] == )
{
break;
}
}
}
} LL num[size << ], x[size];
void pushup(LL rt)
{
num[rt] = num[rt << ] + num[rt << | ];
}
void build( LL l, LL r, LL rt)
{
num[rt] = ;
if( l == r) return;
LL m = (l + r) >> ;
build(lson);
build(rson);
} LL qurey( LL L, LL R, LL l, LL r, LL rt)
{
if( L <= l && r <= R)
return num[rt];
LL m = (l + r) >> ;
LL ans = ;
if(L <= m) ans+=qurey(L, R, lson);
if(R > m) ans+=qurey(L, R, rson);
return ans;
}
void updata( LL p, LL l, LL r, LL rt)
{
if( l == r)
{
num[rt]++;return;
}
LL m = ( l + r) >> ;
if( p <= m) updata(p, lson);
else updata(p, rson);
pushup(rt);
}
LL a[MAXN + ];
int main()
{
LL n;
init();
check[] = ;
for(LL i = ; i <= MAXN; i++ ){
if(!check[i]) check[i] = i;
} LL sum = ;
build(, MAXN , );
for( LL i= ; i <= MAXN; i++)
{
LL sum = ;
//scanf("%lld", &x[i]);
sum = qurey(, check[i], , MAXN , ); a[i] = sum;
updata(check[i], , MAXN, ); }
LL t;
scanf("%lld",&t);
while(t--){
LL x;
scanf("%lld",&x);
printf("%lld\n",a[x]);
}
return ;
}

B题

并查集

没有蘑菇的建树,求出有多少个没有蘑菇的路,然后求出有蘑菇的路就行

AC代码:

/**
/*@author Victor
/*language C++
*/
//#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
//#include<map>
#include<set>
//#define DEBUG
#define RI register ll
using namespace std;
typedef long long ll;
//typedef __ll128 lll;
const ll N=+;
const ll MOD=1e9+;
const double PI = acos(-1.0);
const double EXP = 1E-;
const ll INF = 0x3f3f3f3f;
#define pii pair<ll,ll>
#define pll pair<ll,ll>
#define pil pair<ll , ll>
#define pli pair<ll,ll>
#define pdl pair<double,ll>
#define pld pair<ll,double>
#define pdd pair<double,double>
#define iput(n) scanf("%lld",&n);
#define iiput(a,n) scanf("%lld%lld",&a,&n);
#define iiiput(a,b,c) scanf("%lld%lld%lld",&a,&b,&c);
#define dput(n) scanf("%lf",&n);
#define llput(n) scanf("%lld",&n);
#define cput(n) scanf("%s",n);
#define puti(n) prllf("%lld\n",n);
#define putll(n) prllf("%lld\n",n);
#define putd(n) prllf("%lfd\n",n);
#define _cls(n) memset(n,0,sizeof(n));
#define __cls(n) memset(n,INF,sizeof(n));
//priority_queue <ll,vector<ll>,greater<ll> > Q;//优先队列递增
//priority_queue<ll>Q;//递减
//map<ll,ll>mp;
//set<ll>st;
//stack<>st;
//queue<>Q;
/***********************************************/
//加速输入挂
# define IOS ios::sync_with_stdio(false)
# define FOR(i,a,n) for(ll i=a; i<=n; ++i)
//求二进制中1的个数
//__builtin_popcount(n);
//求2^k
//#define (ll)Pow(2,k) (1LL<<k)
#define to_1(n) __builtin_popcount(n)
//树状数组
#define lowbit(x) (x&-x)
ll fa[];
ll pre[];
void init(ll n){
for(ll i = ;i <= n;i++)
fa[i] = i;
} ll find(ll x) {
if(fa[x] == x) return x; return fa[x] = find(fa[x]);
} void merge(ll x,ll y) {
ll xi = find(x);
ll yi = find(y);
if(xi == yi)
return;
else
fa[xi] = yi;
return ;
} int main(){
ll n;
IOS;
cin >> n;
init(n);
for(ll i = ; i < n ; i++){
ll u,v,w;
cin >> u >> v >> w;
if(w == ) continue;
merge(u,v);
}
for(ll i = ; i <= n;i++){
++pre[find(i)];
} ll sum = ;
for(ll i = ; i <= n;i++){
if(pre[i])
sum += pre[i] * (n - pre[i]);
}
cout << sum << endl;
return ;
}

C题

N次最短路

AC代码:

/**
/*@author Victor
/*language C++
*/
#include <cmath>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <stack>
using namespace std;
#define MAXN 200010
#define LEN 200010
#define INF 1e9+7
#define MODE 1000000
#define pi acos(-1)
#define g 9.8
typedef long long ll;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct edge{
ll next,to,w;
}; edge G[MAXN*];
ll root;
ll num=;
ll cnt=;
ll head[MAXN<<];
ll depth[MAXN<<];//深度
ll first[MAXN<<];//首次出现编号
ll dir[MAXN<<];//距离
ll que[MAXN<<];//队列
ll par[MAXN];//并查集父节点
bool vis[MAXN];
ll dp[MAXN][];
void init(ll n){for(ll i=;i<=n;i++)par[i]=i;}//初始化并查集
ll _find(ll x){if(par[x]==x)return x;else return par[x]=_find(par[x]);}//查询并查集祖先
void unite(ll x,ll y){x=_find(x),y=_find(y);if(x==y)return;else par[x]=y;}//合并节点
void add(ll u,ll v,ll w){G[num].w=w;G[num].to=v;G[num].next=head[u];head[u]=num++;}//前向星建图
void dfs(ll u,ll dep)//dfs建图
{
vis[u]=true;
que[++cnt]=u;first[u]=cnt;depth[cnt]=dep;
for(ll k=head[u];k!=-;k=G[k].next)
{
ll v=G[k].to,w=G[k].w;
if(!vis[v]){
dir[v]=dir[u]+w;
dfs(v,dep+);
que[++cnt]=u;depth[cnt]=dep;
}
}
}
//ST表求LCA
void ST(ll n)
{
for(ll i=;i<=n;i++)
dp[i][] = i;
for(ll j=;(<<j)<=n;j++)
{
for(ll i=;i+(<<j)-<=n;i++)
{
ll a = dp[i][j-] , b = dp[i+(<<(j-))][j-];
dp[i][j] = depth[a]<depth[b]?a:b;
}
}
}
//两个节点之间的路径深度最小的就是LCA
ll RMQ(ll l,ll r)
{
ll k=;
while((<<(k+))<=r-l+)
k++;
ll a = dp[l][k], b = dp[r-(<<k)+][k]; //保存的是编号
return depth[a]<depth[b]?a:b;
}
ll LCA(ll u ,ll v)
{
ll x = first[u] , y = first[v];
if(x > y) swap(x,y);
ll res = RMQ(x,y);
return que[res];
}
ll n,m,c;
int main()
{
scanf("%lld",&n);
m = n - ;
num=,cnt=;
memset(head,-,sizeof(head));
memset(vis,,sizeof(vis));
init(n);
for(ll i=;i<m;i++)
{
ll u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
add(u,v,w);
add(v,u,w);
unite(u,v);
}
ll u1,v1,w1;
scanf("%lld%lld%lld",&u1,&v1,&w1);
for(ll i=;i<=n;i++)
{
if(_find(i)==i){
dir[i]=;
dfs(i,);
}
}
ST(*n-);
scanf("%lld",&c);
while(c--)
{
ll u,v;
scanf("%lld%lld",&u,&v); ll lca=LCA(u,v);
ll mid1 = dir[u]+dir[v]-*dir[lca];
ll lca1=LCA(u,u1);
ll lca2 = LCA(v1,v);
ll mid2 = dir[u]+dir[u1]-*dir[lca1] + dir[v]+dir[v1]-*dir[lca2] + w1;
ll lca3=LCA(u,v1); ll lca4 = LCA(u1,v);
ll mid3 = dir[u]+dir[v1]-*dir[lca3] + dir[v]+dir[u1]-*dir[lca4] + w1;
ll mine;
if(mid1 > mid2){
mine = mid2;
}
else mine = mid1; if(mine > mid3){
mine = mid3;
}
//else mine = mid; printf("%lld\n",mine); }
return ;
}

D题

gcd求最简分数

AC代码:

//                .*/@@@]]``...
// .,@@ ,[[\@@@@]`.. .**.*]]]]/@@@@@@@\]]]]*.**.
// *@@ ,OOOO]` .[@@@]]@@@@@@[[[[`* *,[[[\@@@@@@]]`.. .*....*****.....
// .=@^ OOOOOOOOO\ @@@[` .[\@@@\]/@@@@@@@@@@@@@@@@@\`.
// .=@^,OOOOOOOOO[` [@@ *]]]]]]. =@^.
// .@@*=OOOOOO/[` \OOOOOOOOOOO^ =@^.
// .@@ /OOOOO/* ,,OOOOOOO^ @@*
// .@@.OOOO/. ,OOOOOOO^=@^.
// .=@^\OO` =O/OOO @@`.
// .=@^ ,OOO*,@/.
// *@@` [. @@*.
// *@@. @@@^.
// .=@^ =@^.
// *@@ ,]. .@@*
// .=@^ =/ [\@\ .\@^.
// ./@` */@\.
// *@@ *^@@*
// *@@ ]]` ,]]. *^@@.
// .,@/ @@@@@@^ =@@@@@@ ,^@@.
// .@@ =@@@@@@@ @@@@@@@^ =^@@.
// .=@^ @@@@@@^ =@@@@@@ *o^@@*
// .=@^ ,ooooo^ [[` [[[[[` ,[[. ./oooo^ /o=@/.
// .=@^ ,ooooo^ *oooooo. =o/@@`.
// *@@ ** =oo=@/.
// .,@\ /oo\@@.
// .,@@ ,oo//@/.
// .*\@\ ,oo/\@@`.
// .,\@@] ]]]]] .]oo[]@@@`.
// ..,\@@@@]]]* *@@@OOO@@@@\. .,]]]@@@@@/`*.
// .*.*[[[@@@@@/ @@O@@@OO@@@O@@` \@@@[*...
// ./@^ =@OOOO@@@@OOOO@@^ *o\@^.
// .=@/ ,@@@@@@@@@@@@O@O@@OOO@@^,]@@^ =^@@`.
// *@@ ,@@OO@@@@@O@OOO@@@[. *o/@@.
// .=@^ /@@O@@@O@@@OOO@@ ]. \o\@^.
// .@@ ,]]@@@@@@OO@@@@O@@OOO@@\]]]/@@/ =o/@@*
// .,@/ ,[[* \@@OOO@OOOOOOO@@[[[` *o\@@^.
// .=@^ \@@OOOOOOOOO@@@\` oo=@\.
// .@@. .[@@@@@OOOOOO@@` =o^@@*
// *@@ *@@OO@@@@@@ =o^@@.
// *@@ ,@@@[ *` =o^@@^.
// .*.................................................
//
/**
/*@author Victor
/*language C++
*/
//#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
//#include<map>
#include<set>
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=+;
const int MOD=1e9+;
const double PI = acos(-1.0);
const double EXP = 1E-;
const int INF = 0x3f3f3f3f;
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int , ll>
#define pli pair<ll,int>
#define pdl pair<double,ll>
#define pld pair<ll,double>
#define pdd pair<double,double>
#define iput(n) scanf("%d",&n);
#define iiput(a,n) scanf("%d%d",&a,&n);
#define iiiput(a,b,c) scanf("%d%d%d",&a,&b,&c);
#define dput(n) scanf("%lf",&n);
#define llput(n) scanf("%lld",&n);
#define cput(n) scanf("%s",n);
#define puti(n) printf("%d\n",n);
#define putll(n) printf("%lld\n",n);
#define putd(n) printf("%lfd\n",n);
#define _cls(n) memset(n,0,sizeof(n));
#define __cls(n) memset(n,INF,sizeof(n));
//priority_queue <int,vector<int>,greater<int> > Q;//优先队列递增
//priority_queue<int>Q;//递减
//map<ll,ll>mp;
//set<ll>st;
//stack<>st;
//queue<>Q;
/***********************************************/
//加速输入挂
# define IOS ios::sync_with_stdio(false)
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
//求二进制中1的个数
//__builtin_popcount(n);
//求2^k
//#define (ll)Pow(2,k) (1LL<<k)
#define to_1(n) __builtin_popcount(n)
//树状数组
#define lowbit(x) (x&-x)
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll qpow(ll p,ll q){ll f=;while(q){if(q&)f=f*p;p=p*p;q>>=;}return f;}
ll exgcd(ll l,ll r,ll &x,ll &y){if(r==){x=;y=;return l;}else{ll d=exgcd(r,l%r,y,x);y-=l/r*x;return d;}}
//求a关于m的乘法逆元
ll mod_inverse(ll a,ll m){ll x,y;if(exgcd(a,m,x,y)==)/*ax+my=1*/return (x%m+m)%m;return -;/*不存在*/}
//快速乘
ll qmul(ll a,ll b,ll m){ll ans=;ll k=a;ll f=;/*f是用来存负号的*/if(k<){f=-;k=-k;}if(b<){f*=-;b=-b;}while(b){if(b&)ans=(ans+k)%m;k=(k+k)%m;b>>=;}return ans*f;}
//中国剩余定理CRT (x=ai mod mi)
ll china(ll n, ll *a,ll *m) {ll M=,y,x=,d;for(ll i = ; i <= n; i++) M *= m[i];for(ll i = ; i <= n; i++) {ll w = M /m[i]; exgcd(m[i], w, d, y);/*m[i]*d+w*y=1*/ x = (x + y*w*a[i]) % M;}return (x+M)%M;}
//筛素数,全局:int cnt,prime[N],p[N];
//void isprime(){cnt = 0;memset(prime,true,sizeof(prime));for(int i=2; i<N; i++){if(prime[i]){p[cnt++] = i;for(int j=i+i; j<N; j+=i)prime[j] = false;}}}
//快速求逆元
//void inverse(){inv[1] = 1;for(int i=2;i<N;i++){if(i >= M) break;inv[i] = (M-M/i)*inv[M%i]%M;}}
//组合数取模,n和m 10^5时,预处理出逆元和阶乘
/*
ll fac[N]={1,1},inv[N]={1,1},f[N]={1,1};
ll C(ll a,ll b){
if(b>a)return 0;
return fac[a]*inv[b]%M*inv[a-b]%M;
}
void init(){//快速计算阶乘的逆元
for(int i=2;i<N;i++){
fac[i]=fac[i-1]*i%M;
f[i]=(M-M/i)*f[M%i]%M;
inv[i]=inv[i-1]*f[i]%M;
}
}
*/ int main(){
int t;
cin >> t;
while(t--){
ll a,b,c,d;
cin >> a >> b >> c >> d;
ll sum =( b - a + ) * (d - c + );
ll su;
if(a > d || c > b) su = ;
else if(a > c)
{
if(b > d)
su = d - a + ;
else su = b - a + ;
}
else if( a <= c){
if(b > d)
su = d - c + ;
else su = b - c + ; }
if(su == ) printf("0/1\n");
else {
if(sum % su == ){
printf("1/%lld\n",sum / su);
}
else {
printf("%lld/%lld\n",su / gcd(su,sum) , sum / gcd(su,sum));
}
}
}
return ;
}

E题

暴力最小遍历

AC代码:

/**
/*@author Victor
/*language C++
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[],b[][];
int main(){
ll n,k; scanf("%lld%lld",&n,&k);
ll min = ;
for(int j = ; j < n ; j++){ for(int i = ; i < k ; i++ ){
scanf("%lld",&a[i]);
}
sort(a,a+k); for(int z = ; z < k; z++ )
{
b[j][z] = a[z];
// cout << a[z] << endl;
} } for(int i = ; i < k ; i++){
for(int j = ; j < n - ; j++){
min += abs(b[j][i] - b[j + ][i]);
// cout << min << endl;
}
} printf("%lld\n",min);
return ;
}

F题

枚举每点的最短路求和求最小值

AC代码:

/**
/*@author Victor
/*language C++
*/
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<map>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<fstream>
using namespace std;
typedef pair<int,int> PII;
const int MAXN=1e4+;
const int INF=0x3f3f3f3f;
bool vis[MAXN];
int dist[MAXN],head[MAXN],tot;
int pre[MAXN]; struct Edge
{
int from,to,cost,nxt;
Edge(){}
Edge(int _from,int _to,int _cost):from(_from),to(_to),cost(_cost){}
}e[MAXN*]; void addedge(int u,int v,int w)
{
e[tot].from=u;e[tot].to=v;e[tot].cost=w;
e[tot].nxt=head[u];head[u]=tot++;
} struct qnode
{
int c,v;
qnode(int _c=,int _v=):c(_c),v(_v){}
bool operator < (const qnode &rhs) const {return c>rhs.c;}
}; void Dijkstra(int n,int st)//点的编号从1开始
{
memset(vis,false,sizeof(vis));
for(int i=;i<=n;i++) dist[i]=INF;
priority_queue<qnode> pq;
while(!pq.empty()) pq.pop();
dist[st]=;
pq.push(qnode(,st));
qnode frt;
while(!pq.empty())
{
frt=pq.top(); pq.pop();
int u=frt.v;
if(vis[u]) continue;
vis[u]=true;
for(int i=head[u];i!=-;i=e[i].nxt)
{
int to=e[i].to;
int cost=e[i].cost;
if(dist[to]>dist[u]+cost)
{
dist[to]=dist[u]+cost;
pre[to]=u;
pq.push(qnode(dist[to],to));
}
}
}
} int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==&&m==) break;
tot=;memset(head,-,sizeof(head));
int u,v,w;
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);addedge(v,u,w);
}
int st,ed;
int sum = ;
int mine = INF; for(int st = ; st <= n;st++){ Dijkstra(n,st);
for(int i = ; i <= n;i++ ) { sum += dist[i];
}
if(sum < mine){
ed = st;
mine = sum ;
}
sum = ; } printf("%d %d\n",mine , ed);
}
return ;
}

G题

逆序对 + 线段树(归并排序

AC代码:

/**
/*@author Victor
/*language C++
*/
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#define _cls(a) memset(a,0,sizeof(a))
typedef long long ll;
using namespace std; ll n, a[], tmpA[], cnt = ;
ll p[]; void merge_sort(ll l, ll r, ll *A) {
if (l >= r) return ;
ll mid = (l + r) >> ;
merge_sort(l, mid, A);
merge_sort(mid + , r, A);
ll pl = l, pr = mid + , tmpp = ;
while(pl <= mid && pr <= r) {
if (A[pl] <= A[pr]) tmpA[tmpp++] = A[pl++];
else tmpA[tmpp++] = A[pr++], cnt += mid - pl + ;
}
while(pl <= mid) tmpA[tmpp++] = A[pl++];
while(pr <= r) tmpA[tmpp++] = A[pr++];
for (ll i = ; i < tmpp; i++) A[i + l] = tmpA[i];
} int main() {
ll t;
scanf("%lld",&t);
while(t--){
_cls(p);
_cls(a);
_cls(tmpA);
cnt = ;
scanf("%lld", &n);
for (ll i = ; i <= n; i++){
ll x;
scanf("%lld", &x);
p[x] = i;
}
for (ll i = ; i <= n; i++) {
ll x;
scanf("%lld", &x);
a[i] = p[x];
}
merge_sort(, n, a);
printf("%lld\n", cnt);
}
return ;
}

H题

二分 + 前缀和

AC代码:

/**
/*@author Victor
/*language C++
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll; struct name
{
ll w, v;
};
struct name1
{
ll a, b;
};
ll s[];
ll o[];
name p[ + ];
name1 p1[ + ]; int main(){ ll n,m ,S;
scanf("%lld%lld%lld",&n,&m,&S);
for(ll i = ; i <= n;i ++ )
{
ll w,v;
scanf("%lld%lld",&p[i].w,&p[i].v);
}
ll l = , r = ;
ll W ;
for(ll i = ; i <= m; i++){ scanf("%lld %lld",&p1[i].a,&p1[i].b);
}
ll sum = ;
for(ll k = ; k <= ; k++){
W = (l + r) / ;
memset(s,,sizeof(s));
memset(o,,sizeof(o));
for(ll j = ; j <= n; j++ ){
if(W <= p[j].w){
s[j] = s[j - ] + p[j].v;
o[j] = + o[j - ];
}
else {
s[j] = s[j - ] ;
o[j] = o[j - ] ;
}
} ll mine = ;
ll H = ;
// ll sum = 2000000;
for(ll i = ; i <= m ; i++ ){
H += (s[p1[i].b] - s[p1[i].a - ]) * (o[p1[i].b] - o[p1[i].a - ]);
}
if(H < S) {
r = W ;
}
else l = W; mine = abs(H - S); if(sum > mine) sum = mine;
}
printf("%lld\n",sum);
return ;
}

I题

完全背包 + 快速幂

AC代码:

/**
/*@author Victor
/*language C++
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t;
ll dp[ + ];
ll qpow(ll a,ll b,ll m){
ll ans=;
ll k=a;
while(b){
if(b&)ans=ans*k%m;
k=k*k%m;
b>>=;
}
return ans;
}int main(){ scanf("%lld",&t);
while(t -- ){
memset(dp,,sizeof(dp));
ll n, m;
dp[] = ;
// dp[0] = 1;
scanf("%lld%lld",&n,&m);
if(m==) dp[n] = qpow(,n, + );
else{ for(int i = ;i < m;i++){
dp[i] = ;
} for(int i = m ; i <= n;i++){ dp[i] += dp[i - ] + dp[i - m];
dp[i] %= ( + );
}
}
// for(int i = 0 ; i <= n ; i++ ){
// printf("%d\n",dp[i]);
// }
//printf("%d",dp[n]);
printf("%lld\n",dp[n] % ( + )); }
return ;
}

J题

线段树

AC代码:

/**
/*@author Victor
/*language C++
*/
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#define LL long long
using namespace std; LL INF = 0x3f3f3f3f;
const LL MAX = + ; LL Sum[MAX << ];
LL Add[MAX << ]; LL A[MAX]; //PushUp函数更新节点信息 ,这里是求和
void PushUp(LL rt){
Sum[rt] = Sum[rt<<] + Sum[rt<< |];
//prLLf("888sum[%ll] = %ll\n", rt, Sum[rt]);
} //PushDown下推标记
void PushDown(LL rt,LL ln,LL rn){
//ln,rn为左子树,右子树的数字数量。
if(Add[rt]){
//下推标记
Add[rt<<]+=Add[rt];
Add[rt<<|]+=Add[rt];
//修改子节点的Sum使之与对应的Add相对应
Sum[rt<<]+=Add[rt]*ln;
Sum[rt<<|]+=Add[rt]*rn;
//清除本节点标记
Add[rt]=;
}
}
//Build函数建树
void Build(LL l,LL r,LL rt){ //l,r表示当前节点区间,rt表示当前节点编号
//prLLf("l = %ll r = %ll\n", l, r);
if(l==r) {//若到达叶节点
Sum[rt] = A[l];//储存数组值
//prLLf("A[%ll] = %lld\n", l, A[l]);
//prLLf("sum[%ll] = %ll\n", rt, Sum[rt]);
return;
}
LL m=(l+r)>>;
//左右递归
Build(l,m,rt<<);
Build(m+,r,rt<<|);
//更新信息
PushUp(rt);
//prLLf("888sum[%ll] = %ll\n", rt, Sum[rt]);
} //点修改 A[L] + C
void Update(LL L,LL C,LL l,LL r,LL rt){//l,r表示当前节点区间,rt表示当前节点编号
if(l==r){//到叶节点,修改
Sum[rt] = C;
//prLLf("sum[%ll] = %ll\n", rt, Sum[rt]);
return;
}
LL m=(l+r)>>;
PushDown(rt,m-l+,r-m);//下推标记
//根据条件判断往左子树调用还是往右
if(L <= m) Update(L,C,l,m,rt<<);
else Update(L,C,m+,r,rt<<|);
PushUp(rt);//子节点更新了,所以本节点也需要更新信息
} //区间修改
void UpdateRange(LL L,LL R,LL C,LL l,LL r,LL rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
if(L <= l && r <= R){//如果本区间完全在操作区间[L,R]以内
Sum[rt]+=C*(r-l+);//更新数字和,向上保持正确
Add[rt]+=C;//增加Add标记,表示本区间的Sum正确,子区间的Sum仍需要根据Add的值来调整
return ;
}
LL m=(l+r)>>;
PushDown(rt,m-l+,r-m);//下推标记
//这里判断左右子树跟[L,R]有无交集,有交集才递归
if(L <= m) UpdateRange(L,R,C,l,m,rt<<);
if(R > m) UpdateRange(L,R,C,m+,r,rt<<|);
PushUp(rt);//更新本节点信息
} //区间查询, 这里是求和
LL QueryRange(LL L,LL R,LL l,LL r,LL rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
if(L <= l && r <= R){
//在区间内,直接返回
return Sum[rt];
}
LL m=(l+r)>>;
//下推标记,否则Sum可能不正确
PushDown(rt,m-l+,r-m); //累计答案
LL ANS= ;
if(L <= m) ANS += QueryRange(L,R,l,m,rt<<);
if(R > m) ANS += QueryRange(L,R,m+,r,rt<<|);
return ANS;
} LL Query(LL l, LL r, LL rt, LL k){
if(l == r){
return l;
} LL m = (l + r) >> ; if(Sum[(rt << )] >= k){
return Query(l, m, rt << , k);
} else{
return Query(m + , r, rt << | , k - Sum[rt << ]);
}
} //建树 Build(1,n,1); //点修改 Update(L,C,1,n,1); //区间修改 UpdateRange(L,R,C,1,n,1); //区间查询 LL ANS=Query(L,R,1,n,1); int main(int argc, char const *argv[])
{
LL n, q;
scanf("%lld%lld", &n, &q); for(LL i = ; i <= n; i++){
scanf("%lld", &A[i]);
} Build(, n, );
while(q--){
char op[];
LL a , b , c;
scanf("%s",op);
if (op[] == '') {
scanf("%lld%lld%lld",&a,&b,&c);
UpdateRange(a,b,c,,n,);
} else if(op[] == ''){
scanf("%lld%lld%lld",&a,&b,&c);
UpdateRange(a , b , -c , , n , );
}
else if(op[] == ''){
scanf("%lld%lld",&a,&c);
Update(a,c,,n,);
}
else if(op[] == ''){
scanf("%lld%lld",&a,&b);
printf("%lld\n",QueryRange(a , b , , n , )); }
}
return ;
}

CSUST 集训队选拔赛题解的更多相关文章

  1. 2019CSUST集训队选拔赛题解(二)

    凛冬将至 Description 维斯特洛大陆的原住民是森林之子,他们长得如孩童一般,善于使用石器,威力值35,用树叶树枝作为衣物,在森林里繁衍生息,与万物和平相处.他们会使用古老的魔法(比如绿之视野 ...

  2. 2019CSUST集训队选拔赛题解(三)

    PY学长的放毒题 Description 下面开始PY的香港之行,PY有n个要去的小吃店,这n个小吃店被m条路径联通起来. PY有1个传送石和n−1个传送石碎片. PY可以用传送石标记一个小吃店作为根 ...

  3. 2019CSUST集训队选拔赛题解(一)

    来自ppq的毒瘤线段树 Sneakers   Description 有一天喜欢买鞋的ppq和小伙伴来到了某一家球鞋店,球鞋店有n种球鞋,价格分别为ai,ppq在鞋店兜兜转转,发现鞋店老板会偶尔将某段 ...

  4. CSUST选拔赛题解

    本鶸鸡于本月10号参加了蔽校的选拔赛,成绩差的死,大部分的题都是赛后花了好长时间才补出来的,其中有些题还是靠QAQorz大佬帮忙才能解决,感谢Qls对我的帮助~接下来就附带上我的暴力题解,大佬们有更好 ...

  5. CSUST 四月选拔赛个人题解

    这场比赛演的逼真,感谢队友不杀之恩 总结:卡题了赶紧换,手上捏着的题尽快上机解决 http://csustacm.com:4803/ 1113~1122 1113:六学家 题意:找出满足ai+aj=a ...

  6. 2015苏州大学ACM-ICPC集训队选拔赛(3)题解

    第三次校赛链接:快戳我 1001 考虑前半组数,我们只需要标记每个数出现的次数,再加上这个数之前的数出现的次数,即为这个数在m次操作中总共需要翻转的次数(即求前缀和),再根据翻转的奇偶性判断最后这个位 ...

  7. 江西理工大学南昌校区acm选拔赛题解

    第一题略 第二题 #include<stdio.h> int main() { int a1,a2,a3,b1,b3,b2,c1,c2,c3,n,sum,d1,d2,d3,i; scanf ...

  8. hdu 2155 小黑的镇魂曲(dp) 2008信息工程学院集训队——选拔赛

    感觉蛮坑的一道题. 题意很像一个叫“是男人下100层”的游戏.不过多了个时间限制,要求在限定时间内从某一点下落到地面.还多了个最大下落高度,一次最多下落这么高,要不然会摔死. 一开始想dp的,然后想了 ...

  9. 2019年华南理工大学软件学院ACM集训队选拔赛 Round1

    TIps: 1.所有代码中博主使用了scanf和printf作为输入输出  2.代码中使用了define LL long long 所以在声明变量的时候 LL其实就等价于long long 希望这两点 ...

随机推荐

  1. leetcode.双指针.88合并两个有序数组-Java

    1. 具体题目 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明: 初始化 nums1 和 nums2 的元素数量分别 ...

  2. 安装gmpy2

    本来只想做个RSA的题,结果环境就搭了好久 首先想用 pip install gmpy2 发现缺东西,要安装gmp,mpfr,mpc 安装: mkdir -p $HOME/src mkdir -p $ ...

  3. DB2临时表空间的作用

    临时表空间分为系统临时表空间和用户临时表空间 系统临时表空间用来存储各种数据操作(排序.重组表.创建索引.连接表)中所需的内部临时数据,虽然可以创建任意多个系统临时表空间,但建议用户只使用大多数表所使 ...

  4. JQ广告弹窗&随机抽奖————JQ

    1.JQ广告弹窗 <div id="flo"> <img src="image.jpeg"> </div> <scri ...

  5. 【转载】Elasticsearch--java操作之QueryBuilders构建搜索Query

    原文地址:https://www.cnblogs.com/pypua/articles/9459941.html package com.elasticsearch; import org.elast ...

  6. 循环结构select 语法

  7. go语言从例子开始之Example23.通道缓冲

    默认通道是 无缓冲 的,这意味着只有在对应的接收(<- chan)通道准备好接收时,才允许进行发送(chan <-).可缓存通道允许在没有对应接收方的情况下,缓存限定数量的值. 不支持缓冲 ...

  8. Java中File的处理

    不知道“文件”和“文件路径”是否存在的处理情况 1.如果是文件,先获取文件父路径,没有就生成父路径,然后再生成文件. public class TestMain { public static voi ...

  9. iview select下拉框的蜜汁小坑

    前言 最近使用iview的select下拉选择器,遇到一个很神奇的问题:选中下拉框里面的一个值,但是再去点下拉框的时候就只剩刚才选中的数据了.感觉应该是插件把刚才选中的数据当做的搜索条件,所以需要做的 ...

  10. Base64和3DES算法

    Base64加密算法 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,可用于在HTTP环境下传递较长的标识信息.它的优点是算法效率高,编码出来的结果比较简短,同时也具有不可读性. ...