2024.5.19 【人啊...想要保护重要东西的时候,就真的能变得很坚强。】
Sunday 四月十二
模拟赛
在完成了分配任务之后,西部 314 来到了楼兰古城的西部。
相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(V),一个部落崇拜铁锹(∧),他们分别用 V 和 ∧ 的形状来代表各自部落的图腾。
西部 314 在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了 n 个点,经测量发现这 n 个点的水平位置和竖直位置是两两不同的。
西部 314 认为这幅壁画所包含的信息与这 n 个点的相对位置有关,因此不妨设坐标分别为 (1,y1),(2,y2),…,(n,yn)
,其中 y1∼yn是 1 到 n 的一个排列。
西部 314打算研究这幅壁画中包含着多少个图腾。
如果三个点 (i,yi),(j,yj),(k,yk)满足 1≤i<j<k≤n且 yi>yj,yj<yk,则称这三个点构成 V 图腾;
如果三个点 (i,yi),(j,yj),(k,yk)满足 1≤i<j<k≤n且 yi<yj,yj>yk,则称这三个点构成 ∧ 图腾;
西部 314想知道,这 n个点中两个部落图腾的数目。
因此,你需要编写一个程序来求出 V 的个数和 ∧ 的个数。
输入格式
第一行一个数 n
。
第二行是 n个数,分别代表 y1,y2,…,yn。
输出格式
两个数,中间用空格隔开,依次为 V 的个数和 ∧ 的个数。
数据范围
对于所有数据,n≤200000
,且输出答案不会超过 int64
。
y1∼yn是 1 到 n 的一个排列。
输入样例:
5
1 5 3 2 4
输出样例:
3 4
树状数组求解逆序对,
就是当前数字前比他小的总数,
离散化后,
用当前数位减去前面小的就是后面小的。
前面总数减去前面小的就是前面大的,
组合求解即可。
//2024.5.19
//by white_ice
#include<bits/stdc++.h>
using namespace std;
#define itn long long
#define int long long
constexpr int oo = 200005;
int minout;
int maxout;
struct node{int val,num,id;}a[oo];
bool cmp (node x,node y){return x.val>y.val;}
bool cmp1(node a,node b){return a.val<b.val;}
int n;
int c[oo];
void add(int x,int k){for(int i=x;i<=n;i+=i&(-i)) c[i]+=k;}
int query(int x){
int sum=0;
for(int i=x;i>0;i-=i&(-i)) sum+=c[i];
return sum;}
int ans;
signed main(){
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i].val),a[i].num=i;
sort(a+1,a+n+1,cmp1);
for (itn i=1;i<=n;i++)
a[i].id = i;
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
int maxp;
itn minp;
int k = a[i].id;
add(a[i].num,1);
maxp=query(a[i].num-1);
minp=a[i].num-1-maxp;
//cout << minp <<' '<<k-1-minp<< ' '<< maxp<<' '<< n-k-maxp << endl;
minout += minp*(k-1-minp);
maxout += maxp*(n-k-maxp);
}
cout << maxout << ' '<<minout;
return 0;
}
附pb_ds抽象做法
//Zn
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define int long long
using namespace std;
using namespace __gnu_pbds;
inline int read()
{
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N=2e5+10;
tree<int,null_type,
std::less<int>,
splay_tree_tag,
tree_order_statistics_node_update>ll,rl;
tree<int,null_type,
std::greater<int>,
splay_tree_tag,
tree_order_statistics_node_update>lg,rg;
int n,a[N],l_l[N],r_l[N],l_g[N],r_g[N];
int ans1,ans2;
signed main()
{
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++)
{
ll.insert(a[i]);
l_l[i]=ll.order_of_key(a[i]);
}
for(int i=n;i>=1;i--)
{
rl.insert(a[i]);
r_l[i]=rl.order_of_key(a[i]);
}
for(int i=1;i<=n;i++)
{
lg.insert(a[i]);
l_g[i]=lg.order_of_key(a[i]);
}
for(int i=n;i>=1;i--)
{
rg.insert(a[i]);
r_g[i]=rg.order_of_key(a[i]);
}
for(int i=1;i<=n;i++)
{
ans1+=l_g[i]*r_g[i];
ans2+=l_l[i]*r_l[i];
}
printf("%lld %lld",ans1,ans2);
return 0;
}
题目描述
有 n 头奶牛,已知它们的身高为 1∼n 且各不相同,但不知道每头奶牛的具体身高。
现在这 n 头奶牛站成一列,已知第 i 头牛前面有 $$A_i$$头牛比它低,求每头奶牛的身高。
输入格式
第 1 行:输入整数 n。
第 2..n 行:每行输入一个整数 $$A_i$$ ,第 i 行表示第 i 头牛前面有 $$A_i$$头牛比它低。 (注意:因为第 1 头牛前面没有牛,所以并没有将它列出)
输出格式
输出包含 n 行,每行输出一个整数表示牛的身高。
第 i 行输出第 i 头牛的身高。
数据范围
\[1≤n≤10^5 \]输入样例:
5
1
2
1
0
输出样例:
2
4
5
3
1
仍然是树状数组求逆序对
二分依次求解答案即可
//2024.5.19
//by white_ice
#include<bits/stdc++.h>
using namespace std;
#define itn int
constexpr int oo = 100005;
itn bitt(itn x){return x&(-x);}
int st[oo];
int n;
int tree[oo];
itn out[oo];
void add(int x,int k){for(int i=x;i<=n;i+=bitt(i))tree[i]+=k;}
int query(int x){
int sum=0;for(int i=x;i>0;i-=(bitt(i)))sum+=tree[i];
return sum;}
int ans;
int main(){
scanf("%d",&n);
for (itn i=1;i<=n;i++)add(i,1);
for(int i=2;i<=n;i++)
scanf("%d",&st[i]);
st[1] = 0;
for(int i=n;i>=1;i--){
int l = 1,r = n;
int ans;
st[i]++;
while(l<=r){
int mid=(l+r)>>1;
if(query(mid)>=st[i]){
ans = mid;
r = mid-1;
}
else
l = mid+1;
}
out[i] = ans;
add(ans,-1);
}
for (itn i=1;i<=n;i++)
cout << out[i] << endl;
return 0;
}
再附上pb_ds抽象做法......
//Zn
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
const int N=1e5+10;
tree<int,null_type,
std::less<int>,
splay_tree_tag,
tree_order_statistics_node_update>tr;
int n,a[N],b[N];
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
tr.insert(i);
for(int i=n;i>=2;i--)
{
b[i]=*tr.find_by_order(a[i]);
tr.erase(tr.find_by_order(a[i]));
}
b[1]=*tr.find_by_order(0);
for(int i=1;i<=n;i++)
printf("%d\n",b[i]);
return 0;
}
题目描述
给定一个长度为
N 的数列 A,以及 M 条指令,每条指令可能是以下两种之一:
C l r d,表示把 A[l],A[l+1],…,A[r] 都加上 d.
Q l r,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。
对于每个询问,输出一个整数表示答案。
输入格式
第一行两个整数 N,M。
第二行 N 个整数 A[i]。
接下来 M 行表示 M 条指令,每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。
数据范围
\[N≤500000,M≤100000, 1≤A[i]≤10_18 ∣d∣≤10_18 \],保证数据在计算过程中不会超过 long long 范围。
输入样例:
5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4
输出样例:
1
2
4
更相减损法告诉我们,
加上一个数后,
我们知道,加上的共同部分减掉了
#include <cmath>
#include <cstdio>
#include <iostream>
#define int long long
const int N = 500005;
struct Node {
int l, r;
long long ans;
} tree[N << 2];
int a[N], b[N], c[N];
long long cnt;
long long gcd(long long x, long long y) {
return y ? gcd(y, x % y) : x;
}
namespace SegmentTree {
inline void build(int rt, int l, int r) {
tree[rt].l = l, tree[rt].r = r;
if(l == r) {
tree[rt].ans = b[l];
return ;
}
int mid = (l + r) >> 1;
build(rt * 2, l, mid);
build(rt * 2 + 1, mid + 1, r);
tree[rt].ans = gcd(tree[rt * 2].ans, tree[rt * 2 + 1].ans);
}
inline void change_point(int rt, int x, int k) {
if(tree[rt].l == tree[rt].r) {
tree[rt].ans += k;
return ;
}
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(mid >= x) change_point(rt * 2, x, k);
else change_point(rt * 2 + 1, x, k);
tree[rt].ans = gcd(tree[rt * 2].ans, tree[rt * 2 + 1].ans);
}
inline void ask(int rt, int l, int r) {
if(tree[rt].l >= l && tree[rt].r <= r) {
cnt = gcd(cnt, tree[rt].ans);
return ;
}
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(l <= mid) ask(rt * 2, l, r);
if(r > mid) ask(rt * 2 + 1, l, r);
}
}
int n;
namespace BIT {
int lowbit(int x) {
return x & (-x);
}
inline void add(int x, int k) {
while(x <= n) {
c[x] += k;
x += lowbit(x);
}
}
int ask(int x) {
long long res = 0;
while(x) {
res += c[x];
x -= lowbit(x);
} return res;
}
}
signed main() {
static int m;
scanf("%lld %lld", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
b[i] = a[i] - a[i - 1];
} SegmentTree::build(1, 1, n);
char c[3];
for (int i = 1; i <= m; i++) {
scanf("%s", c + 1);
if(c[1] == 'C') {
int l, r, d;
scanf("%lld %lld %lld", &l, &r, &d);
SegmentTree::change_point(1, l, d);
BIT::add(l, d);
if(r + 1 <= n) {
SegmentTree::change_point(1, r + 1, -d);
BIT::add(r + 1, -d);
}
} else {
cnt = 0; int l, r;
scanf("%lld %lld", &l, &r);
SegmentTree::ask(1, l + 1, r);
printf("%lld\n", gcd(a[l] + BIT::ask(l), std::abs(cnt)));
}
} return 0;
}
#代码转载自https://www.cnblogs.com/Nicoppa/p/11590181.html
标签:rt,2024.5,19,tree,long,int,ans,include
From: https://www.cnblogs.com/white-ice/p/18200515