2019徐州网络赛

I 题 query  题目链接

题目大意是给一个N(<=1e5) permutation  p (下标从1开始) , 现在定义一种pair( i ,j) ,其满足 min(pi?,pj?)=gcd(pi?,pj?),现在有M (<=1e5) 组区间查询[l,r]询问 满足 l <= i < j <= r 的pair有多少对。

这是一种偏序关系的问题,看了一点CDQ 解偏序的介绍 , 感觉也可以树状数组来搞。
预处理出每个符合要求的点对( l , r )位置,在一维树状数组上修改点对右端位置 r 的值(+1),这些点对排序好后放在gcdp(这些点对的数量是 NlogN级别的)。
然后离线做,存查询对,并排序。按顺序回答查询,如果查询为 [L,R] 就可以二分查找[L,L] 在 gcdp里的位置 ind,然后将gcdp里 ind 位置前 所有的点对 对树状数组的修改还原(-1),再通过树状数组查询 R 的前缀和 ,即是当前查询的答案。(因为这样可以满足树状数组里 [1,R]全部都是  l >= L 的点对施加的影响 , l < L 的点对影响必然在ind位置之前所以被还原了),这是看CDQ偏序得到的想法 。
因为查询是排好序的,所以每一个点对(l , r)给树状数组的影响最多只有两次(+1 与 -1),只要记录上一次ind的位置就可以不重复-1,最坏复杂度 O(2*N*logN*logN + M * log(N*logN) )

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 typedef pair<int,int> pii;
 5 const int maxn = 1e5;
 6 int n,m;
 7 int raw[maxn + 10],ind[maxn + 10];
 8 vector<pii> gcdp;
 9 pii query[maxn+10];
10 int queryp[maxn + 10];
11 int ans[maxn + 10];
12 int Flick[maxn + 10];
13
14 bool cmp(int i,int j){
15     return query[i] < query[j];
16 }
17
18 int lowbit(int x){
19     return x&(-x);
20 }
21
22 void FlickUpdate(int ind,int val){
23     while(ind <= n){
24         Flick[ind] += val;
25         ind += lowbit(ind);
26     }
27 }
28
29 int FlickQuery(int ind){
30     int ret = 0;
31     while(ind > 0){
32         ret += Flick[ind];
33         ind -= lowbit(ind);
34     }
35     return ret;
36 }
37
38 int main(){
39     //__clock_t stt = clock();
40     scanf("%d%d",&n,&m);
41     for(int i=1;i<=n;++i){
42         scanf("%d",&raw[i]);
43         ind[raw[i]] = i;
44     }
45 //    int tot = 0;
46     for(int i=1;i<=n;++i){
47         for(int j = 2 * i;j<=n; j+= i){
48             int L = ind[i] , R = ind[j];
49             if(L >= R) swap(L,R);
50             gcdp.emplace_back(make_pair(L,R));
51         }
52     }
53     sort(gcdp.begin(),gcdp.end());
54 //    puts("gcdmin pair :");
55 //    for(auto item : gcdp) printf("%d %d\n",item.first
56 //        ,item.second);
57 //    puts("");
58     for(auto item : gcdp){
59         int tmp = item.second;
60 //        printf("second : %d\n",tmp);
61         FlickUpdate(tmp,1);
62     }
63
64     for (int j = 1; j <= m; ++j) {
65         int l,r;
66         scanf("%d%d",&l,&r);
67         query[j] = make_pair(l,r);
68         queryp[j] = j;
69     }
70     sort(queryp + 1 ,queryp + 1 + m,cmp);
71 //    puts("query pair :");
72 //    for(int j = 1;j<=m;++j) printf("%d %d\n",query[queryp[j]].first
73 //                ,query[queryp[j]].second);
74 //    puts("");
75     int last = 0;
76     for(int j=1;j<=m;++j){
77         int numq = queryp[j];
78         pii qry = query[numq];
79
80         pii change = make_pair(qry.first,qry.first);
81         int bound = lower_bound(gcdp.begin(),gcdp.end(),change) - gcdp.begin();
82 //        printf("[%d,%d] : %d %d\n",qry.first,qry.second,last,bound);
83         for(int k = last;k<bound ;++k){
84             FlickUpdate(gcdp[k].second,-1);
85         }
86         last = max(bound,last);
87
88         ans[numq] = FlickQuery(qry.second);
89     }
90     for(int j=1;j<=m;++j){
91         printf("%d\n",ans[j]);
92     }
93     //__clock_t edt = clock();
94 //    printf("Used Time : %.3lfms\n", static_cast<double>(edt - stt)/1000.0);
95     return 0;
96 }

开始gcdp的数组大小开少了会RE,后来改用vector ;最初没有记录上一次 ind 的位置导致重复-1,样例太水,还是自己构造的数据发现的。

如果是解多维或者其他大小的偏序关系区间查询问题,如果查询没有强制在线,应该都可以转化成这种离线存查询排序,以最后一维度值做树状数组的查询与修改。而这种做法需要小心每个点的修改次数。

ps:此题还有CDQ与线段树做法。

原文地址:https://www.cnblogs.com/Kiritsugu/p/11493247.html

时间: 2024-07-30 20:33:48

2019徐州网络赛的相关文章

2019徐州网络赛 XKC&#39;s basketball team 线段树

网址:https://nanti.jisuanke.com/t/41387 题意: 大家好,我是训练时长两年半的个人练习生蔡徐坤,我的爱好是唱,跳,rap,篮球. 给出一段长度为$n,(n \leq 1e5)$的序列,对每一个数,求出它和它后面比它大$m$的数中间夹着的数的数量,没有输出$-1$. 题解: 直接建线段树,维护最大值,然后查询时对第$i$个数,搜索区间$[i,n]$之中大于$num[i]+m$的值的位置的最大值,具体操作是先限定区间,然后求出所有合法位置,取最大值,如果搜索不到则返

query 2019徐州网络赛(树状数组)

query \[ Time Limit: 2000 ms \quad Memory Limit: 262144 kB \] 题意 补题才发现比赛的时候读了一个假题意.... 给出长度为 \(n\) 的排列,在给出 \(m\) 次询问,每次询问有一对 \(l.r\),问满足 \(min(ai, aj) = gcd(ai, aj)\) 的 \(pair(i, j)\) 对数. 思路 考虑离线做 先把每个数出现的位置记录下来,然后预处理出所有的 \(pair\). 对于一个数字 \(x\),其满足条件

【2019.09.07】2019徐州网络赛

补题地址:https://www.jisuanke.com/contest/3005?view=challenges 题目: A:? B:? C:? D:? E:? F: G:? 回文树+二进制统计回文串内不同字母数技巧https://blog.csdn.net/Cassie_zkq/article/details/100606270 H: I:? J: K:? L: M:? 原文地址:https://www.cnblogs.com/ncu2019/p/11482910.html

2019徐州网络赛 I J M

I. query 比赛时候没有预处理因子疯狂t,其实预处理出来因子是\(O(nlog(n))\)级别的 每个数和他的因子是一对偏序关系,因此询问转化为(l,r)区间每个数的因子在区间(l,r)的个数 预处理出来每个位置上的数所有因子的位置,用可持久化线段树维护,区间询问 #include<bits/stdc++.h> #define ll long long #define mk make_pair #define ft first #define se second #define pii

2019 徐州网络赛 center

题意:n个点,求最小加上几个点让所有点关于一个点(不需要是点集里面的点)中心对称 题解:双重循环枚举,把中点记录一下,结果是n-最大的中点 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef unsigned long long ull; 5 #define mem(s) memset(s, 0, sizeof(s)) 6 const int INF = 0x3f3f3f3f;

2019徐州网络赛 H.function

题意: 先有\(n=p_1^{k_1}p_2^{k_2}\cdots p_m^{k_m}\),定义\(f(n)=k_1+k_2+\cdots+k_m\). 现在计算 \[ \sum_{i=1}^nf(i!)\% 998244353 \] 思路: 首先注意到\(f\)函数有这样一个性质:\(f(ab)=f(a)+f(b)\). 那么我们化简所求式子有: \[ \begin{aligned} &\sum_{i=1}^nf(i!)\=&\sum_{i=1}^n\sum_{j=1}^if(j)\=

2018徐州网络赛H. Ryuji doesn&#39;t want to study

题目链接: https://nanti.jisuanke.com/t/31458 题解: 建立两个树状数组,第一个是,a[1]*n+a[2]*(n-1)....+a[n]*1;第二个是正常的a[1],a[2],a[3]...a[n] #include "bits/stdc++.h" using namespace std; #define ll long long const int MAXN=1e5+10; ll sum[MAXN],ans[MAXN]; ll num[MAXN];

20180909徐州网络赛题解

目录 20180909徐州网络赛题解 A. Hard to prepare MEANING SOLUTION CODE B. BE, GE or NE MEANING SOLUTION CODE F. Features Track CODE G. Trace MENING SOLUTION CODE H. Ryuji doesn't want to study MEANING CODE I. Characters with Hash CODE J. Maze Designer MEANING S

ACM-ICPC 2018徐州网络赛-H题 Ryuji doesn&#39;t want to study

C*M....死于update的一个long long写成int了 心累 不想写过程了 ******** 树状数组,一个平的一个斜着的,怎么斜都行 题库链接:https://nanti.jisuanke.com/t/31460 #include <iostream> #include <cstring> #define ll long long #define lowbit(x) (x & -x) using namespace std; const int maxn =